Overview of Data
The purpose of this dataset was to help find predictors of diabetes.
The goal is to help medical professionals identify patients with
potential risk factors of diabetes.The dataset contains information on
patient demographics such as age and gender, as well as medical
information including blood glucose levels and hypertension. The
observations in this dataset were obtained from research studies and
healthcare institutions. The dataset was obtained via Kaggle.
Mustafa, T. Z. (2021). Diabetes Prediction Dataset. Kaggle.
https://www.kaggle.com/datasets/iammustafatz/diabetes-prediction-dataset
The dataset consists of 8 predictor variables for diabetes:
gender - the patient’s gender as male or
female.
age - the age of the patient in years.
hypertension - yes or no, on whether the patient
has hypertension.
heart disease - yes or no, on whether the
patient has heart disease.
smoking history - the patient’s smoking history
indicated as never, no info, current, former or not current.
bmi - the patient’s body mass index
(kg/m**2).
HbA1c level - the patient’s average blood sugar
level over the past 2-3 months (%).
blood glucose level - amount of blood sugar in
the patient’s blood (mg/dL).
#load in dataset
data <-read.csv('https://raw.githubusercontent.com/GabbyK8/Datasets/refs/heads/main/diabetes_prediction_dataset.csv')
diabetesd<-data
#change heart disease, diabetes and hypertension to 1 and 0 for easier use in MICE.
data$diabetes <- recode(data$diabetes, "1"="Yes", "0"="No")
data$hypertension <- recode(data$hypertension, "1"="Yes", "0"="No")
data$heart_disease <- recode(data$heart_disease, "1"="Yes", "0"="No")
#plot interaction between diabetes and hypertension.
ggplot(data, aes(x = hypertension, fill = diabetes)) +
geom_bar(position = "dodge") + # Use "stack" for a stacked bar chart
labs (title="Risk of Diabetes by Hypertension", x="Hypertension", y= "Frequency",
fill= "Diabetes")
Comparison of Two Categorical Variables
The purpose of this graph is to show the relationship between having
hypertension and diabetes. For this graph, I changed the values of 1 in
both the diabetes and hypertension variable to “Yes” and the value 0 to
“No.” These integers were meant to represent categorical variables with
1 correlating to being positive for hypertension or diabetes and 0
correlating to being negative to hypertension or diabetes. Based on our
graph, we can see that there is no correlation between having diabetes
and having hypertension, with most patients within our sample having
neither diabetes or hypertension. Thus, hypertension would not be a good
predictor of diabetes within patients.
interact = ggplot(data, aes(x =blood_glucose_level , y = HbA1c_level, group = diabetes, color = diabetes)) +
geom_line(size = 1) + # Lines representing interaction
geom_point(size = 2) + # Points for data
labs(
title = "Interaction of Blood Glucose and HbA1c Levels",
x = "Blood Glucose Level",
y = "HbA1c Level",
color = "Presence of Diabetes"
) +
theme_minimal() +
theme(
plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
axis.text = element_text(size = 12),
legend.position = "top"
)
interact
Comparison of Two Numerical Variables
The two variables being compared here are Blood Glucose Level and
HbA1c Level. HbA1cc is a shortened term for hemoglobin A1c. Hb1Ac level
is a measure of average blood sugar levels over 2-3 months and is
measured in %. Blood glucose level is the amount of blood sugar in a
patients blood at a given time. Our plot shows a correlation between
high levels in HbA1c and blood glucose levels and it’s relationship with
diabetes. This plot suggests patients with high levels of HbA1c and
blood glucose levels are at high risk for diabetes.
#plot of a numerical and categorical variable
boxplot(data$age ~ data$diabetes,
xlab="Presence of Diabetes",
ylab="Patient Age",
col = c("skyblue", "purple"),
main="Visualization of Diabetes by Age",
cex.main = 1.1,
col.main = "navy")
Comparison of a Numerical and Categorical Variables
This chart shows the relationship between age and diabetes diagnosis.
This chart shows that as patients grow older they are at higher risk for
diabetes. This would make age a predictor for diabetes, with the average
age for those without diabetes being 40 years and 60 years for those
with diabetes. However, we can see that we do have a few outliers for
those with diabetes with some patients being diagnosed at 20 or younger.
This could be from the population of people with Type I diabetes which
is usually diagnosed in patients under 20. Our dataset does not
distinguish between type I and type II diabetes.
Conclusion for Comparison of Variables
Diabetes can be predicted using age, blood glucose levels, and HbA1c
levels in patients. However, our results showed hypertension is not a
good predictor of diabetes. Based on our findings, it would be
interesting to look at factors that occur once a patient becomes older
that could lead to diabetes at an older age. As well, diet could be
another factor to look into, such as grams of sugar consumed on a daily
or weekly basis, to see if sugar consumption can predict diabetes.
Another important thing to analyze in future studies would be Type I
versus Type II diabetes, as it could be the reason for some of the
outliers in the boxplot.
Overview of Missing Variables
An important step in data analysis for machine learning is handling
missing values. Missing values in a dataset can occur for many reasons,
but not limited to non-response in surveys, participants leaving the
study, data entry errors and system limitations. If missing values are
not addressed, models can become biased and accuracy of the anaylysis
can decrease. This section examines different imputation strategies to
effectively handle missing values.
The imputation methods we will examine include:
Replacement Imputation for Categorical Features: Mode imputation.
Regression-based Imputation for Numerical Features: Predictive
modeling to estimate missing values.
Multiple Imputation: Advanced methods such as MICE to improve
robustness.
# create random observation ID and replace the corresponding obs with missing
ltr.missing.id <- sample(1:1000, 50, replace = FALSE)
gpa.missing.id <- sample(1:1000, 15, replace = FALSE)
diabetesd$bmi[ltr.missing.id] <- NA
diabetesd$heart_disease[gpa.missing.id] <- NA
diabetesd$smoking_history[diabetesd$smoking_history == "No Info"] <- NA
Mode Imputation for Categorical Variables
In this method, missing variables are replaced with the most frequent
category of the corresponding variable. Mode imputation ensures
consistency and works well when missing values are randomly distributed.
Below, mode imputation is used on the variable, heart disease, which is
1 if the patient has heart disease and 0 if the patient does not have
heart disease.The variable smoking history had current, former, no info,
never, and ever as possible values. No Info indicates that we do not
have information on the participant’s smoking history and will be
treated as a missing values.
original original2 imputed_modehd imputed_modesh
Min. :0.00000 Length:100000 Min. :0.00000 Length:100000
1st Qu.:0.00000 Class :character 1st Qu.:0.00000 Class :character
Median :0.00000 Mode :character Median :0.00000 Mode :character
Mean :0.03943 Mean :0.03942
3rd Qu.:0.00000 3rd Qu.:0.00000
Max. :1.00000 Max. :1.00000
NA's :15
Regression-Based Imputation for Numerical Variables
Using regression models, we can estimate missing values. For the
variable, bmi, we can predict the missing values using estimates from
our model. Bmi is a continuous variable, unlike the previous example
where our values could only be 0 or 1. In this method, a linear model
was created to help create estimates of our values.
#create a dataset for regression impute
regimpute<-diabetesd
# Identify rows where BMI is missing
missing_rows <- which(is.na(diabetesd$bmi)) # Get row indices
# Train a linear model using complete cases
lm_model <- lm(bmi ~ age + blood_glucose_level + HbA1c_level + heart_disease + hypertension + diabetes,
data = regimpute, na.action = na.exclude)
# Impute missing BMI values using the model
diabetesd$bmi[missing_rows] <- predict(lm_model, newdata = regimpute[missing_rows, ])
dep.mi <- bind_rows(
data.frame(value = diabetesd$bmi, imputed = regimpute$bmi))
#imp = "dep.imp1")
i7<-boxplot(diabetesd$bmi,
main = "Mean bmi in Original Data",
xlab = "BMI",
col = "blue",
border = "black",
horizontal = TRUE,
notch = TRUE
)
i8 <-boxplot(regimpute$bmi,
main = "Regression Imputation for BMI",
xlab = "BMI",
col = "red",
border = "black",
horizontal = TRUE,
notch = TRUE
)
MICE Imputation
MICE is multiple imputation techniques used to impute missing values.
This method also uses regression models and accounts for uncertainty by
generating multiple possible values. Using MICE, the variables smoking
history, heart disease, and bmi, can be imputated within one function.
MICE can handle different types of variables, imputates based on the
relationship between variables and it accounts for variability in
missing data.
#plot comparisons for smoking history
g4 <- ggplot(df_imputed, aes(x = smoking_history)) +
geom_bar( fill = "purple", color = "#000000", position = "identity") +
ggtitle("MICE") +
labs(x="Smoking History")+
theme_classic()
g5 <- ggplot(value_imputed, aes(x = original2)) +
geom_bar( fill = "red", color = "#000000", position = "identity") +
ggtitle("Original Smoking History") +
labs(x="Smoking History")+
theme_classic()
g6 <- ggplot(value_imputed, aes(x = imputed_modesh)) +
geom_bar( fill = "blue", color = "#000000", position = "identity") +
ggtitle("Mode-imputed") +
labs(x="Smoking History")+
theme_classic()
plot_grid(g4,g5,g6, nrow=3, ncol=1)
#plot comparisons for bmi
g7<-boxplot(diabetesd$bmi,
main = "Mean BMI in Original Data",
xlab = "BMI",
col = "blue",
border = "black",
horizontal = TRUE,
notch = TRUE
)
g8 <-boxplot(regimpute$bmi,
main = "Regression Imputation for BMI",
xlab = "BMI",
col = "red",
border = "black",
horizontal = TRUE,
notch = TRUE
)
g9 <-boxplot(df_imputed$bmi,
main = "MICE for BMI",
xlab = "BMI",
col = "purple",
border = "black",
horizontal = TRUE,
notch = TRUE
)
model5 <- with(df_mice, lm(diabetes ~ bmi+ heart_disease+ smoking_history ))
summary(pool(model5))
term estimate std.error statistic df
1 (Intercept) -1.589271e-01 0.0042324895 -37.549331 7809.1387
2 bmi 8.389138e-03 0.0001290303 65.016790 98218.7361
3 heart_disease1 2.215433e-01 0.0044014918 50.333683 97912.1342
4 smoking_historyever 4.340230e-03 0.0044699572 0.970978 758.3466
5 smoking_historyformer 3.921079e-02 0.0034267231 11.442648 1492.5796
6 smoking_historynever -4.314363e-05 0.0026854000 -0.016066 835.6005
7 smoking_historynot current 6.005163e-03 0.0038588408 1.556209 545.3864
p.value
1 7.985880e-284
2 0.000000e+00
3 0.000000e+00
4 3.318688e-01
5 4.026967e-29
6 9.871856e-01
7 1.202385e-01
The statistics above show the summary of the newly imputed missing
variables through MICE. Based on our p-values, smoking history will most
likely not be chosen for the final model as it’s significance level is
greater than 0.05, indicating an insignificant predictor variable.
Skewness
Skewness is a measure of symmetry within a distribution. The skewness
measurements below are of the variables age, bmi, HbA1c level, and blood
glucose level, respectively. When skewness is equal to 0, we can assume
the data is normally distributed. When skewness is greater than 0, our
data is positively skewed, while a value less than zero indicates
negatively skewed data. For the diabetes dataset, the variables bmi and
blood glucose level are 1 or about 1, which indicate a significant right
skew in the distribution.
age1<- skewness(df_imputed$age)
bmi1<-skewness(df_imputed$bmi)
HbA1c1<-skewness( df_imputed$HbA1c_level)
glucose1<-skewness(df_imputed$blood_glucose_level)
mytable<-data.frame(age1,bmi1,HbA1c1, glucose1)
pander(mytable, caption= "Skewness of Numeric Variables",position="center")
Skewness of Numeric Variables
| -0.05198 |
1.043 |
-0.06685 |
0.8216 |
Analyzing Data
The next step is to find which variables are significantly important
when trying to predict diabetes. By using feature selection, we are able
to predict possible best fit models for our variable, diabetes. For this
data, we will focus on logistic regression. The variables of interest,
diabetes, is a binary variable indicating linear regression would not
make an ideal model.
Random Forest
First, we will look at the best model selected by feature selection
through random forest:
# Prepare the data
df_trans$diabetes <- as.factor(df_trans$diabetes)
# Set up RFE control with random forest
control <- rfeControl(functions = rfFuncs, method = "cv", number = 10)
# Apply RFE to identify top features
results <- rfe(
x = df_trans[, !colnames(df_trans) %in% "diabetes"],
y = df_trans$diabetes,
sizes = c(1:9),
rfeControl = control
)
# Print the selected features
models<-data.frame(predictors(results))
pander(models, caption="Random Forest Selected Model",position="center")
Random Forest Selected Model
| HbA1c_level |
| blood_glucose_level |
| bmi |
| heart_disease |
| age |
| hypertension |
| gender |
The table shows the selected variables random forest has selected to
use for our model
Stepwise Logistic Regression
Next, let’s look and stepwise logistic regression
#Stepwise Logistic Regression
# Fit a full logistic regression model with all predictors
full_model <- glm(diabetes ~ ., data = df_trans, family = binomial)
# Perform stepwise selection (default is backward elimination)
step_model1 <- step(full_model, direction = "both")
Start: AIC=23046.9
diabetes ~ gender + age + hypertension + heart_disease + smoking_history +
bmi + HbA1c_level + blood_glucose_level
Df Deviance AIC
- smoking_history 4 23028 23044
<none> 23023 23047
- gender 1 23077 23099
- heart_disease 1 23176 23198
- hypertension 1 23308 23330
- bmi 1 24361 24383
- age 1 25095 25117
- blood_glucose_level 1 30572 30594
- HbA1c_level 1 34857 34879
Step: AIC=23043.94
diabetes ~ gender + age + hypertension + heart_disease + bmi +
HbA1c_level + blood_glucose_level
Df Deviance AIC
<none> 23028 23044
+ smoking_history 4 23023 23047
- gender 1 23086 23100
- heart_disease 1 23184 23198
- hypertension 1 23314 23328
- bmi 1 24369 24383
- age 1 25191 25205
- blood_glucose_level 1 30581 30595
- HbA1c_level 1 34865 34879
pander(summary(step_model1))
| (Intercept) |
-9.99 |
0.1105 |
-90.37 |
0 |
| gender |
0.2702 |
0.03536 |
7.641 |
2.15e-14 |
| age |
1.034 |
0.02428 |
42.58 |
0 |
| hypertension |
0.8032 |
0.04665 |
17.22 |
1.977e-66 |
| heart_disease1 |
0.7626 |
0.06015 |
12.68 |
7.801e-37 |
| bmi |
10.24 |
0.2809 |
36.44 |
1.124e-290 |
| HbA1c_level |
2.491 |
0.03768 |
66.12 |
0 |
| blood_glucose_level |
10.3 |
0.149 |
69.11 |
0 |
(Dispersion parameter for binomial family taken to be 1 )
| Null deviance: |
58163 on 99999 degrees of freedom |
| Residual deviance: |
23028 on 99992 degrees of freedom |
The coefficients shown above are the ones stepwise logistic
regression has chosen for the final model. They are HbA1c level, blood
glucose level, bmi, hypertension, gender, and age.
Both selection types selected the same model! However I will still go
through the steps of cross-validation as though I was comparing the two
models.
Cross-Validation
Let’s explore cross-validation to see which model is best fit. For
logistic regression, it is meaningful to look at accuracy and kappa.
#add classification
df_trans$diabetes<- factor(ifelse(df_trans$diabetes==1, "Yes","No"))
train_control <- trainControl(
method = "cv", # cross-validation
number = 10, # 10-fold
classProbs = TRUE # use if you're tracking AUC, Sensitivity, etc.
)
#run CV model
cv_model <- train(
diabetes ~ hypertension + gender +age + HbA1c_level + blood_glucose_level + heart_disease + bmi,
data=df_trans,
method = "glm",
family = "binomial",
trControl = train_control
)
pander(print(cv_model))
Generalized Linear Model
1e+05 samples 7e+00 predictors 2e+00 classes: ‘No’, ‘Yes’
No pre-processing Resampling: Cross-Validated (10 fold) Summary of
sample sizes: 90000, 90000, 90000, 90000, 90000, 90000, … Resampling
results:
Accuracy Kappa
0.95934 0.7012814
Accuracy shows the overall correctness of the model predictions and
kappa measures the levels of agreement between variables. Values closer
to 1 suggest higher accuracy and better agreement. This model suggests
high accuracy and high agreement based on the values.
ROC Curve and AOC Curve
Confusion Matrices
ROC is also known as Receiver Operating
Characteristic Analysis. It is a technique using graphs that evaluates
the performance of a binary model. Before plotting the ROC curve, it is
necessary to calculate the true positive rate (TPR) and false positive
rate (FPR). Below, are confusion matrices that were used to calculate
those values.
#ROC and AUC
df_trans$diabetes <- as.factor(df_trans$diabetes)
# fit a logistic
model.logit <- glm(diabetes ~ age + gender+ bmi+hypertension + heart_disease + blood_glucose_level+ HbA1c_level , family = binomial, data = df_trans)
# predict probability of P(Y = "Yes")
probabilities <- round(as.vector(predict(model.logit, type = "response")),3)
#
thresholds <- c(0.0, 0.25, 0.5, 0.75, 1.0)
# Loop through thresholds and create confusion matrices
for (threshold in thresholds) {
cat("\nConfusion Matrix for Threshold =", threshold, "\n")
# Convert probabilities to predictions
# am: 1 = manual transmission, 0 = automatic transmission
predictions <- ifelse(probabilities > threshold, "Yes", "No")
all_levels <- union(levels(factor(df_trans$diabetes)), levels(factor(predictions)))
# Generate confusion matrix
cm <- confusionMatrix(factor(predictions, levels=all_levels), factor(df_trans$diabetes,levels=all_levels), positive = "Yes")
print(cm$table)
}
Confusion Matrix for Threshold = 0
Reference
Prediction No Yes
No 352 0
Yes 8148 91500
Confusion Matrix for Threshold = 0.25
Reference
Prediction No Yes
No 4217 144
Yes 4283 91356
Confusion Matrix for Threshold = 0.5
Reference
Prediction No Yes
No 5308 868
Yes 3192 90632
Confusion Matrix for Threshold = 0.75
Reference
Prediction No Yes
No 6322 3340
Yes 2178 88160
Confusion Matrix for Threshold = 1
Reference
Prediction No Yes
No 8500 91500
Yes 0 0
ROC Curve
#create ROC curve
TPR = c(1,91500/(91500+0), 91356/(91356+144), 90632/(90632+868), 88160/(88160+3340), 0/(91500+0))
FPR = c(1,352/(352+8148), 4282/(4282+4218), 3193/(5307+3193), 2178/(2178+6322), 0/(8500+0))
plot(FPR, TPR, type = "b", main = "An Illustrative ROC Curve", col ="blue",
xlab="1 - Specifity (FPR)", ylab = "Sensitivity (TPR)")
# add a off-diagonal representing random guess algorithm in binary prediction
abline(0,1, lty = 2, col = "red")
# legend
legend("bottomright", c("Logistic Model", "Random Guess"),
col=c("blue", "red"), lty = 1:2, bty="n", cex = 0.9)

AUC (Area under the Curve)
AUC quantifies the performance of the ROC curve into
a single value that ranges from 0 to 1. The plot below uses the Riemann
Sum approximation to estimate the area under the curve.
#AUC
TPR = round(c(1,91500/(91500+0), 91356/(91356+144), 90632/(90632+868), 88160/(88160+3340), 0/(91500+0)),3)
FPR = round(c(1,352/(352+8148), 4282/(4282+4218), 3193/(5307+3193), 2178/(2178+6322), 0/(8500+0)),3)
TPR0 = TPR[7:1]
FPR0 = FPR[7:1]
#plot(FPR0, TPR0, type = "b")
datSenSpe = data.frame(TPR0, FPR0)
ggROC = ggplot(data = datSenSpe, aes(x = FPR0, y=TPR0)) +
geom_line(col = "steelblue") +
geom_point(col = "red") +
geom_segment(x = FPR0, y = 0, xend = FPR0, yend = TPR0, color = 4) +
geom_segment(x = 0, y = 0, xend = FPR0[7], yend = 0, color = 6) +
ggtitle("Approximating the AUC of Logistic Model") +
xlab("1-specificity (FPR)") +
ylab("Sensitivity (TPR)") +
annotate("text", x = 0.025, y = 0.125, label= "A") +
annotate("text", x = 0.105, y = 0.5, label = "B") +
annotate("text", x = 0.605, y = 0.5, label = "C") +
theme(plot.title = element_text(hjust = 0.5),
legend.position = c(0.8, 0.2),
plot.margin = unit(c(0.15, 0.15, 0.75, 0.15), "inches"),
axis.line = element_line(size = 2, colour = "navy", linetype=1))
# partition the region under the ROC into trapezoids
ggplotly(ggROC)
AUC Value
The are under the curve is equal to 0.9795 which is close to 1, thus
indicating an ideal model.
A<-(0.041*1)/2
B<- ((0.504-0.041)*1)
C<- ((1-0.504)*1)
AUC<- A+B+C
pander(AUC, caption= "Area under the Curve", position="Center")
0.9795
Conclusion for Model Fit
Our best fit model is : \[
\text{ Diabetes} = 9.99 - 0.27\times \text{gender} - 1.03\times
\text{age} -0.8\times \text{hypertension} - 0.76\times \text{heart
disease} -10.24\times \text{bmi} - 2.49\times \text{HbA1c level}
-10.3\times \text{blood glucose level}
\]
The best fit model was selected based on a variety of different
features. Both stepwise selection and random forest selected the model
as best fit. After running performance analyses on the model, the model
was shown to be of high performance. This means that the variables
chosen for the final model are significant for predicting diabetes. The
model chose not to select smoking history as significant predictor for
the response variable. A possible suggestion for this would be to reduce
the number of response values to a binary response. Such as, “Have you
ever smoked?” and have the response be “Yes” or “No”. This could help in
predicting the relationship between smoking and diabetes.
LS0tCnRpdGxlOiAiQXBwbGllZCBNYWNoaW5lIExlYXJuaW5nIGZvciBEYXRhIEFuYWx5c2lzIgphdXRob3I6ICJHYWJyaWVsbGEgS2hhbGlsIgpkYXRlOiAiMjAyNS0wMi0xOCIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIHRvY19mbG9hdDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMKICAgIHRoZW1lOiBsdW1lbgogIHdvcmRfZG9jdW1lbnQ6IAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgZmlnX2NhcHRpb246IHllcwogICAga2VlcF9tZDogeWVzCiAgcGRmX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogbm8KICAgIGZpZ193aWR0aDogMwogICAgZmlnX2hlaWdodDogMwplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCgpgYGB7PWh0bWx9Cgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoKLyogQ2FzY2FkaW5nIFN0eWxlIFNoZWV0cyAoQ1NTKSBpcyBhIHN0eWxlc2hlZXQgbGFuZ3VhZ2UgdXNlZCB0byBkZXNjcmliZSB0aGUgcHJlc2VudGF0aW9uIG9mIGEgZG9jdW1lbnQgd3JpdHRlbiBpbiBIVE1MIG9yIFhNTC4gaXQgaXMgYSBzaW1wbGUgbWVjaGFuaXNtIGZvciBhZGRpbmcgc3R5bGUgKGUuZy4sIGZvbnRzLCBjb2xvcnMsIHNwYWNpbmcpIHRvIFdlYiBkb2N1bWVudHMuICovCgpoMS50aXRsZSB7ICAvKiBUaXRsZSAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgdGhlIHJlcG9ydCB0aXRsZSAqLwogIGZvbnQtc2l6ZTogMjJweDsKICBmb250LXdlaWdodDogYm9sZDsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOwp9Cmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgYXV0aG9ycyAgKi8KICBmb250LXNpemU6IDE4cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsKICBjb2xvcjogbmF2eTsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgdGhlIGRhdGUgICovCiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7CiAgY29sb3I6IERhcmtCbHVlOwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBmb250LXdlaWdodDogYm9sZDsKfQpoMSB7IC8qIEhlYWRlciAxIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgbGV2ZWwgMSBzZWN0aW9uIHRpdGxlICAqLwogICAgZm9udC1zaXplOiAyMnB4OwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGNlbnRlcjsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwp9CmgyIHsgLyogSGVhZGVyIDIgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAyIHNlY3Rpb24gdGl0bGUgKi8KICAgIGZvbnQtc2l6ZTogMjBweDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KCmgzIHsgLyogSGVhZGVyIDMgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDMgc2VjdGlvbiB0aXRsZSAgKi8KICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgpoNCB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCA0IHNlY3Rpb24gdGl0bGUgICovCiAgICBmb250LXNpemU6IDE4cHg7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBkYXJrcmVkOwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKYm9keSB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0KCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9CgpwIHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQoKPC9zdHlsZT4KYGBgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IAojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikKICAgbGlicmFyeShrbml0cikKfQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpCmxpYnJhcnkodGlkeXZlcnNlKQp9CmlmICghcmVxdWlyZSgiR0dhbGx5IikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygiR0dhbGx5IikKbGlicmFyeShHR2FsbHkpCn0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCMgc29tZXRpbWVzLCB5b3UgY29kZSBtYXkgcHJvZHVjZSB3YXJuaW5nIG1lc3NhZ2VzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiAKICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAjIHlvdSBjYW4gYWxzbyBkZWNpZGUgd2hldGhlciB0byBpbmNsdWRlIHRoZSBvdXRwdXQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBvdXRwdXQgZmlsZS4KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQQogICAgICAgICAgICAgICAgICAgICAgKSAgCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFZJTSkgCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoSG1pc2MpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwbG90bHkpCmxpYnJhcnkoRGVzY1Rvb2xzKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkobWljZSkKbGlicmFyeShtb21lbnRzKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHJlc2hhcGUyKSAgIyBGb3IgZGF0YSByZXNoYXBpbmcKbGlicmFyeShjYXJldCkKbGlicmFyeShwUk9DKQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkKbGlicmFyeShmYXN0RHVtbWllcykKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KHBhbmRlcikKYGBgCiMgT3ZlcnZpZXcgb2YgRGF0YQoKVGhlIHB1cnBvc2Ugb2YgdGhpcyBkYXRhc2V0IHdhcyB0byBoZWxwIGZpbmQgcHJlZGljdG9ycyBvZiBkaWFiZXRlcy4gVGhlIGdvYWwgaXMgdG8gaGVscCBtZWRpY2FsIHByb2Zlc3Npb25hbHMgaWRlbnRpZnkgcGF0aWVudHMgd2l0aCBwb3RlbnRpYWwgcmlzayBmYWN0b3JzIG9mIGRpYWJldGVzLlRoZSBkYXRhc2V0IGNvbnRhaW5zIGluZm9ybWF0aW9uIG9uIHBhdGllbnQgZGVtb2dyYXBoaWNzIHN1Y2ggYXMgYWdlIGFuZCBnZW5kZXIsIGFzIHdlbGwgYXMgbWVkaWNhbCBpbmZvcm1hdGlvbiBpbmNsdWRpbmcgYmxvb2QgZ2x1Y29zZSBsZXZlbHMgYW5kIGh5cGVydGVuc2lvbi4gVGhlIG9ic2VydmF0aW9ucyBpbiB0aGlzIGRhdGFzZXQgd2VyZSBvYnRhaW5lZCBmcm9tIHJlc2VhcmNoIHN0dWRpZXMgYW5kIGhlYWx0aGNhcmUgaW5zdGl0dXRpb25zLiBUaGUgZGF0YXNldCB3YXMgb2J0YWluZWQgdmlhIEthZ2dsZS4gCgpNdXN0YWZhLCBULiBaLiAoMjAyMSkuICpEaWFiZXRlcyBQcmVkaWN0aW9uIERhdGFzZXQqLiBLYWdnbGUuIGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvaWFtbXVzdGFmYXR6L2RpYWJldGVzLXByZWRpY3Rpb24tZGF0YXNldAoKVGhlIGRhdGFzZXQgY29uc2lzdHMgb2YgOCBwcmVkaWN0b3IgdmFyaWFibGVzIGZvciBkaWFiZXRlczoKCiogKipnZW5kZXIqKiAtIHRoZSBwYXRpZW50J3MgZ2VuZGVyIGFzIG1hbGUgb3IgZmVtYWxlLgoKKiAqKmFnZSoqIC0gdGhlIGFnZSBvZiB0aGUgcGF0aWVudCBpbiB5ZWFycy4KCiogKipoeXBlcnRlbnNpb24qKiAtIHllcyBvciBubywgb24gd2hldGhlciB0aGUgcGF0aWVudCBoYXMgaHlwZXJ0ZW5zaW9uLgoKKiAqKmhlYXJ0IGRpc2Vhc2UqKiAtIHllcyBvciBubywgb24gd2hldGhlciB0aGUgcGF0aWVudCBoYXMgaGVhcnQgZGlzZWFzZS4KCiogKipzbW9raW5nIGhpc3RvcnkqKiAtIHRoZSBwYXRpZW50J3Mgc21va2luZyBoaXN0b3J5IGluZGljYXRlZCBhcyBuZXZlciwgbm8gaW5mbywgY3VycmVudCwgZm9ybWVyIG9yIG5vdCBjdXJyZW50LgoKKiAqKmJtaSoqIC0gdGhlIHBhdGllbnQncyBib2R5IG1hc3MgaW5kZXggKGtnL20qKjIpLgoKKiAqKkhiQTFjIGxldmVsKiogLSB0aGUgcGF0aWVudCdzIGF2ZXJhZ2UgYmxvb2Qgc3VnYXIgbGV2ZWwgb3ZlciB0aGUgcGFzdCAyLTMgbW9udGhzICglKS4KCiogKipibG9vZCBnbHVjb3NlIGxldmVsKiogLSBhbW91bnQgb2YgYmxvb2Qgc3VnYXIgaW4gdGhlIHBhdGllbnQncyBibG9vZCAobWcvZEwpLgoKCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsIGZpZy5jYXA9J1RoZSBwbG90IG9mIHNob3dzIHRoZSBmcmVxdWVuY3kgb2YgcGF0aWVudHMgd2l0aCBkaWFiZXRlcyBhbmQgaHlwZXJ0ZW5zaW9uLiBUaGUgcGxvdCBpbmRpYWN0ZXMgYSBoaWdoZXIgZnJlcXVlbmN5IG9mIHBhdGllbnRzIG5vdCBoYXZpbmcgZGlhYmV0ZXMgYW5kIG5vdCBoYXZpbmcgaHlwZXJ0ZW5zaW9uLiBUaGVyZSBkb2VzIG5vdCBzZWVtIHRvIGJlIGFuIGludGVyYWN0aW9uIGJldHdlZW4gaGF2aW5nIGRpYWJldGVzIGFuZCBoYXZpbmcgaHlwZXJ0ZW5zaW9uIGJhc2VkIG9uIHRoZSBsb3cgZnJlcXVlbmN5IG9mIHBhdGllbnRzIGhhdmluZyBib3RoLiAnfQojbG9hZCBpbiBkYXRhc2V0CmRhdGEgPC1yZWFkLmNzdignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0dhYmJ5SzgvRGF0YXNldHMvcmVmcy9oZWFkcy9tYWluL2RpYWJldGVzX3ByZWRpY3Rpb25fZGF0YXNldC5jc3YnKQpkaWFiZXRlc2Q8LWRhdGEKCiNjaGFuZ2UgaGVhcnQgZGlzZWFzZSwgZGlhYmV0ZXMgYW5kIGh5cGVydGVuc2lvbiB0byAxIGFuZCAwIGZvciBlYXNpZXIgdXNlIGluIE1JQ0UuCmRhdGEkZGlhYmV0ZXMgPC0gcmVjb2RlKGRhdGEkZGlhYmV0ZXMsICIxIj0iWWVzIiwgIjAiPSJObyIpCmRhdGEkaHlwZXJ0ZW5zaW9uIDwtIHJlY29kZShkYXRhJGh5cGVydGVuc2lvbiwgIjEiPSJZZXMiLCAiMCI9Ik5vIikKZGF0YSRoZWFydF9kaXNlYXNlIDwtIHJlY29kZShkYXRhJGhlYXJ0X2Rpc2Vhc2UsICIxIj0iWWVzIiwgIjAiPSJObyIpCgojcGxvdCBpbnRlcmFjdGlvbiBiZXR3ZWVuIGRpYWJldGVzIGFuZCBoeXBlcnRlbnNpb24uCmdncGxvdChkYXRhLCBhZXMoeCA9IGh5cGVydGVuc2lvbiwgZmlsbCA9IGRpYWJldGVzKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikgKyAjIFVzZSAic3RhY2siIGZvciBhIHN0YWNrZWQgYmFyIGNoYXJ0CiAgbGFicyAodGl0bGU9IlJpc2sgb2YgRGlhYmV0ZXMgYnkgSHlwZXJ0ZW5zaW9uIiwgeD0iSHlwZXJ0ZW5zaW9uIiwgeT0gIkZyZXF1ZW5jeSIsCiAgICAgICAgZmlsbD0gIkRpYWJldGVzIikKCmBgYAoKIyMgQ29tcGFyaXNvbiBvZiBUd28gQ2F0ZWdvcmljYWwgVmFyaWFibGVzCgpUaGUgcHVycG9zZSBvZiB0aGlzIGdyYXBoIGlzIHRvIHNob3cgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGhhdmluZyBoeXBlcnRlbnNpb24gYW5kIGRpYWJldGVzLiBGb3IgdGhpcyBncmFwaCwgSSBjaGFuZ2VkIHRoZSB2YWx1ZXMgb2YgMSBpbiBib3RoIHRoZSBkaWFiZXRlcyBhbmQgaHlwZXJ0ZW5zaW9uIHZhcmlhYmxlIHRvICJZZXMiIGFuZCB0aGUgdmFsdWUgMCB0byAiTm8uIiBUaGVzZSBpbnRlZ2VycyB3ZXJlIG1lYW50IHRvIHJlcHJlc2VudCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgd2l0aCAxIGNvcnJlbGF0aW5nIHRvIGJlaW5nIHBvc2l0aXZlIGZvciBoeXBlcnRlbnNpb24gb3IgZGlhYmV0ZXMgYW5kIDAgY29ycmVsYXRpbmcgdG8gYmVpbmcgbmVnYXRpdmUgdG8gaHlwZXJ0ZW5zaW9uIG9yIGRpYWJldGVzLiBCYXNlZCBvbiBvdXIgZ3JhcGgsIHdlIGNhbiBzZWUgdGhhdCB0aGVyZSBpcyBubyBjb3JyZWxhdGlvbiBiZXR3ZWVuIGhhdmluZyBkaWFiZXRlcyBhbmQgaGF2aW5nIGh5cGVydGVuc2lvbiwgd2l0aCBtb3N0IHBhdGllbnRzIHdpdGhpbiBvdXIgc2FtcGxlIGhhdmluZyBuZWl0aGVyIGRpYWJldGVzIG9yIGh5cGVydGVuc2lvbi4gVGh1cywgaHlwZXJ0ZW5zaW9uIHdvdWxkIG5vdCBiZSBhIGdvb2QgcHJlZGljdG9yIG9mIGRpYWJldGVzIHdpdGhpbiBwYXRpZW50cy4KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwPSdUaGUgcGxvdCBzaG93cyB0aGUgaW50ZXJhY3Rpb24gYmV0d2VlbiBibG9vZCBnbHVjb3NlIGxldmVscyBhbmQgSGJBMWMgbGV2ZWxzIG9uIGRpYWJldGVzLiBCYXNlZCBvbiB0aGUgcGxvdCwgaGlnaGVyIGJsb29kIGdsdWNvc2UgbGV2ZWxzIGFuZCBIYkExYyBsZXZlbHMgYXJlIHBvc2l0aXZlbHkgY29ycmVsYXRlZCB3aXRoIHRoZSBwcmVzZW5jZSBvZiBkaWFiZXRlcy4gSW4gY29tcGFyaXNvbiwgbG93ZXIgbGV2ZWxzLCBpbmRpY2F0ZSB0aGF0IGEgcGF0aWVudCB3aWxsIG1vcmUgY29tbW9ubHkgbm90IGhhdmUgZGlhYmV0ZXMuIFRoZSBoZWlnaHQgb2YgdGhlIHBvaW50cyBzaG93biBmb3IgZGlhYmV0ZXMgcmVwcmVzZW50IHRoZSBsZXZlbHMgb2YgSGJBMWMsIGJhc2VkIG9uIHRoZSBwbG90LCBIYkExYyBsZXZlbHMgcHJlZGljdCB0aGUgcHJlc2VuY2Ugb2YgZGlhYmV0ZXMgbW9yZSBvZnRlbiB0aGFuIGJsb29kIGdsdWNvc2UgbGV2ZWxzLiAnfQoKCmludGVyYWN0ID0gZ2dwbG90KGRhdGEsIGFlcyh4ID1ibG9vZF9nbHVjb3NlX2xldmVsICwgeSA9IEhiQTFjX2xldmVsLCBncm91cCA9IGRpYWJldGVzLCBjb2xvciA9IGRpYWJldGVzKSkgKwogIGdlb21fbGluZShzaXplID0gMSkgKyAgIyBMaW5lcyByZXByZXNlbnRpbmcgaW50ZXJhY3Rpb24KICBnZW9tX3BvaW50KHNpemUgPSAyKSArICMgUG9pbnRzIGZvciBkYXRhCiAgbGFicygKICAgIHRpdGxlID0gIkludGVyYWN0aW9uIG9mIEJsb29kIEdsdWNvc2UgYW5kIEhiQTFjIExldmVscyIsCiAgICB4ID0gIkJsb29kIEdsdWNvc2UgTGV2ZWwiLAogICAgeSA9ICJIYkExYyBMZXZlbCIsCiAgICBjb2xvciA9ICJQcmVzZW5jZSBvZiBEaWFiZXRlcyIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41KSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIKICApCmludGVyYWN0CgpgYGAKIyMgQ29tcGFyaXNvbiBvZiBUd28gTnVtZXJpY2FsIFZhcmlhYmxlcwoKVGhlIHR3byB2YXJpYWJsZXMgYmVpbmcgY29tcGFyZWQgaGVyZSBhcmUgQmxvb2QgR2x1Y29zZSBMZXZlbCBhbmQgSGJBMWMgTGV2ZWwuIEhiQTFjYyBpcyBhIHNob3J0ZW5lZCB0ZXJtIGZvciBoZW1vZ2xvYmluIEExYy4gSGIxQWMgbGV2ZWwgaXMgYSBtZWFzdXJlIG9mIGF2ZXJhZ2UgYmxvb2Qgc3VnYXIgbGV2ZWxzIG92ZXIgMi0zIG1vbnRocyBhbmQgaXMgbWVhc3VyZWQgaW4gJS4gQmxvb2QgZ2x1Y29zZSBsZXZlbCBpcyB0aGUgYW1vdW50IG9mIGJsb29kIHN1Z2FyIGluIGEgcGF0aWVudHMgYmxvb2QgYXQgYSBnaXZlbiB0aW1lLiBPdXIgcGxvdCBzaG93cyBhIGNvcnJlbGF0aW9uIGJldHdlZW4gaGlnaCBsZXZlbHMgaW4gSGJBMWMgYW5kIGJsb29kIGdsdWNvc2UgbGV2ZWxzIGFuZCBpdCdzIHJlbGF0aW9uc2hpcCB3aXRoIGRpYWJldGVzLiBUaGlzIHBsb3Qgc3VnZ2VzdHMgcGF0aWVudHMgd2l0aCBoaWdoIGxldmVscyBvZiBIYkExYyBhbmQgYmxvb2QgZ2x1Y29zZSBsZXZlbHMgYXJlIGF0IGhpZ2ggcmlzayBmb3IgZGlhYmV0ZXMuCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsIGZpZy5jYXA9J1RoZSBib3hwbG90IHNob3dzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBhZ2UgYW5kIHByZXNlbmNlIG9mIGRpYWJldGVzLiBUaGUgYm94cGxvdCBzaG93cyB0aGF0IG9sZGVyIHBhdGllbnRzIG9uIGF2ZXJhZ2UgYXJlIG1vcmUgb2Z0ZW4gaGF2ZSBkaWFiZXRlcy4gVGhlcmUgYXJlIGEgZmV3IG91dGxpZXJzIGluIHRoZSBkaWFiZXRlcyBwb3B1bGF0aW9uIHRoYXQgYXBwZWFyIHRvIGJlIHVuZGVyIHRoZSBhZ2Ugb2YgMjAgeWVhcnMuIFRoaXMgY291bGQgYmUgcmVwcmVzZW50YXRpdmUgb2YgcGF0aWVudHMgd2l0aCBUeXBlIEkgZGlhYmV0ZXMsIHNpbmNlIHRoZSBkYXRhIGRvZXMgbm90IGRpc3Rpbmd1aXNoIGJldHdlZW4gVHlwZSBJIGFuZCBUeXBlIElJIGRpYWJldGVzLiAnfQoKI3Bsb3Qgb2YgYSBudW1lcmljYWwgYW5kIGNhdGVnb3JpY2FsIHZhcmlhYmxlCiBib3hwbG90KGRhdGEkYWdlIH4gZGF0YSRkaWFiZXRlcywKICAgICAgICAgeGxhYj0iUHJlc2VuY2Ugb2YgRGlhYmV0ZXMiLAogICAgICAgICB5bGFiPSJQYXRpZW50IEFnZSIsCiAgICAgICAgIGNvbCA9IGMoInNreWJsdWUiLCAicHVycGxlIiksCiAgICAgICAgIG1haW49IlZpc3VhbGl6YXRpb24gb2YgRGlhYmV0ZXMgYnkgQWdlIiwKICAgICAgICAgY2V4Lm1haW4gPSAxLjEsCiAgICAgICAgIGNvbC5tYWluID0gIm5hdnkiKQpgYGAKCiMjIENvbXBhcmlzb24gb2YgYSBOdW1lcmljYWwgYW5kIENhdGVnb3JpY2FsIFZhcmlhYmxlcwoKVGhpcyBjaGFydCBzaG93cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gYWdlIGFuZCBkaWFiZXRlcyBkaWFnbm9zaXMuIFRoaXMgY2hhcnQgc2hvd3MgdGhhdCBhcyBwYXRpZW50cyBncm93IG9sZGVyIHRoZXkgYXJlIGF0IGhpZ2hlciByaXNrIGZvciBkaWFiZXRlcy4gVGhpcyB3b3VsZCBtYWtlIGFnZSBhIHByZWRpY3RvciBmb3IgZGlhYmV0ZXMsIHdpdGggdGhlIGF2ZXJhZ2UgYWdlIGZvciB0aG9zZSB3aXRob3V0IGRpYWJldGVzIGJlaW5nIDQwIHllYXJzIGFuZCA2MCB5ZWFycyBmb3IgdGhvc2Ugd2l0aCBkaWFiZXRlcy4gSG93ZXZlciwgd2UgY2FuIHNlZSB0aGF0IHdlIGRvIGhhdmUgYSBmZXcgb3V0bGllcnMgZm9yIHRob3NlIHdpdGggZGlhYmV0ZXMgd2l0aCBzb21lIHBhdGllbnRzIGJlaW5nIGRpYWdub3NlZCBhdCAyMCBvciB5b3VuZ2VyLiBUaGlzIGNvdWxkIGJlIGZyb20gdGhlIHBvcHVsYXRpb24gb2YgcGVvcGxlIHdpdGggVHlwZSBJIGRpYWJldGVzIHdoaWNoIGlzIHVzdWFsbHkgZGlhZ25vc2VkIGluIHBhdGllbnRzIHVuZGVyIDIwLiBPdXIgZGF0YXNldCBkb2VzIG5vdCBkaXN0aW5ndWlzaCBiZXR3ZWVuIHR5cGUgSSBhbmQgdHlwZSBJSSBkaWFiZXRlcy4KCgojIENvbmNsdXNpb24gZm9yIENvbXBhcmlzb24gb2YgVmFyaWFibGVzCgpEaWFiZXRlcyBjYW4gYmUgcHJlZGljdGVkIHVzaW5nIGFnZSwgYmxvb2QgZ2x1Y29zZSBsZXZlbHMsIGFuZCBIYkExYyBsZXZlbHMgaW4gcGF0aWVudHMuIEhvd2V2ZXIsIG91ciByZXN1bHRzIHNob3dlZCBoeXBlcnRlbnNpb24gaXMgbm90IGEgZ29vZCBwcmVkaWN0b3Igb2YgZGlhYmV0ZXMuIEJhc2VkIG9uIG91ciBmaW5kaW5ncywgaXQgd291bGQgYmUgaW50ZXJlc3RpbmcgdG8gbG9vayBhdCBmYWN0b3JzIHRoYXQgb2NjdXIgb25jZSBhIHBhdGllbnQgYmVjb21lcyBvbGRlciB0aGF0IGNvdWxkIGxlYWQgdG8gZGlhYmV0ZXMgYXQgYW4gb2xkZXIgYWdlLiBBcyB3ZWxsLCBkaWV0IGNvdWxkIGJlIGFub3RoZXIgZmFjdG9yIHRvIGxvb2sgaW50bywgc3VjaCBhcyBncmFtcyBvZiBzdWdhciBjb25zdW1lZCBvbiBhIGRhaWx5IG9yIHdlZWtseSBiYXNpcywgdG8gc2VlIGlmIHN1Z2FyIGNvbnN1bXB0aW9uIGNhbiBwcmVkaWN0IGRpYWJldGVzLiBBbm90aGVyIGltcG9ydGFudCB0aGluZyB0byBhbmFseXplIGluIGZ1dHVyZSBzdHVkaWVzIHdvdWxkIGJlIFR5cGUgSSB2ZXJzdXMgVHlwZSBJSSBkaWFiZXRlcywgYXMgaXQgY291bGQgYmUgdGhlIHJlYXNvbiBmb3Igc29tZSBvZiB0aGUgb3V0bGllcnMgaW4gdGhlIGJveHBsb3QuIAoKCiMgT3ZlcnZpZXcgb2YgTWlzc2luZyBWYXJpYWJsZXMKCkFuIGltcG9ydGFudCBzdGVwIGluIGRhdGEgYW5hbHlzaXMgZm9yIG1hY2hpbmUgbGVhcm5pbmcgaXMgaGFuZGxpbmcgbWlzc2luZyB2YWx1ZXMuIE1pc3NpbmcgdmFsdWVzIGluIGEgZGF0YXNldCBjYW4gb2NjdXIgZm9yIG1hbnkgcmVhc29ucywgYnV0IG5vdCBsaW1pdGVkIHRvIG5vbi1yZXNwb25zZSBpbiBzdXJ2ZXlzLCBwYXJ0aWNpcGFudHMgbGVhdmluZyB0aGUgc3R1ZHksIGRhdGEgZW50cnkgZXJyb3JzIGFuZCBzeXN0ZW0gbGltaXRhdGlvbnMuIElmIG1pc3NpbmcgdmFsdWVzIGFyZSBub3QgYWRkcmVzc2VkLCBtb2RlbHMgY2FuIGJlY29tZSBiaWFzZWQgYW5kIGFjY3VyYWN5IG9mIHRoZSBhbmF5bHlzaXMgY2FuIGRlY3JlYXNlLiBUaGlzIHNlY3Rpb24gZXhhbWluZXMgZGlmZmVyZW50IGltcHV0YXRpb24gc3RyYXRlZ2llcyB0byBlZmZlY3RpdmVseSBoYW5kbGUgbWlzc2luZyB2YWx1ZXMuCgpUaGUgaW1wdXRhdGlvbiBtZXRob2RzIHdlIHdpbGwgZXhhbWluZSBpbmNsdWRlOgoKUmVwbGFjZW1lbnQgSW1wdXRhdGlvbiBmb3IgQ2F0ZWdvcmljYWwgRmVhdHVyZXM6IE1vZGUgaW1wdXRhdGlvbi4KClJlZ3Jlc3Npb24tYmFzZWQgSW1wdXRhdGlvbiBmb3IgTnVtZXJpY2FsIEZlYXR1cmVzOiBQcmVkaWN0aXZlIG1vZGVsaW5nIHRvIGVzdGltYXRlIG1pc3NpbmcgdmFsdWVzLgoKTXVsdGlwbGUgSW1wdXRhdGlvbjogQWR2YW5jZWQgbWV0aG9kcyBzdWNoIGFzIE1JQ0UgdG8gaW1wcm92ZSByb2J1c3RuZXNzLgoKYGBge3J9CiMgY3JlYXRlIHJhbmRvbSBvYnNlcnZhdGlvbiBJRCBhbmQgcmVwbGFjZSB0aGUgY29ycmVzcG9uZGluZyBvYnMgd2l0aCBtaXNzaW5nCmx0ci5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjEwMDAsIDUwLCByZXBsYWNlID0gRkFMU0UpCmdwYS5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjEwMDAsIDE1LCByZXBsYWNlID0gRkFMU0UpIApkaWFiZXRlc2QkYm1pW2x0ci5taXNzaW5nLmlkXSA8LSBOQQpkaWFiZXRlc2QkaGVhcnRfZGlzZWFzZVtncGEubWlzc2luZy5pZF0gPC0gTkEKZGlhYmV0ZXNkJHNtb2tpbmdfaGlzdG9yeVtkaWFiZXRlc2Qkc21va2luZ19oaXN0b3J5ID09ICJObyBJbmZvIl0gPC0gTkEKCmBgYAoKIyMgTW9kZSBJbXB1dGF0aW9uIGZvciBDYXRlZ29yaWNhbCBWYXJpYWJsZXMKCkluIHRoaXMgbWV0aG9kLCBtaXNzaW5nIHZhcmlhYmxlcyBhcmUgcmVwbGFjZWQgd2l0aCB0aGUgbW9zdCBmcmVxdWVudCBjYXRlZ29yeSBvZiB0aGUgY29ycmVzcG9uZGluZyB2YXJpYWJsZS4gTW9kZSBpbXB1dGF0aW9uIGVuc3VyZXMgY29uc2lzdGVuY3kgYW5kIHdvcmtzIHdlbGwgd2hlbiBtaXNzaW5nIHZhbHVlcyBhcmUgcmFuZG9tbHkgZGlzdHJpYnV0ZWQuIEJlbG93LCBtb2RlIGltcHV0YXRpb24gaXMgdXNlZCBvbiB0aGUgdmFyaWFibGUsIGhlYXJ0IGRpc2Vhc2UsIHdoaWNoIGlzIDEgaWYgdGhlIHBhdGllbnQgaGFzIGhlYXJ0IGRpc2Vhc2UgYW5kIDAgaWYgdGhlIHBhdGllbnQgZG9lcyBub3QgaGF2ZSBoZWFydCBkaXNlYXNlLlRoZSB2YXJpYWJsZSBzbW9raW5nIGhpc3RvcnkgaGFkIGN1cnJlbnQsIGZvcm1lciwgbm8gaW5mbywgbmV2ZXIsIGFuZCBldmVyIGFzIHBvc3NpYmxlIHZhbHVlcy4gTm8gSW5mbyBpbmRpY2F0ZXMgdGhhdCB3ZSBkbyBub3QgaGF2ZSBpbmZvcm1hdGlvbiBvbiB0aGUgcGFydGljaXBhbnQncyBzbW9raW5nIGhpc3RvcnkgYW5kIHdpbGwgYmUgdHJlYXRlZCBhcyBhIG1pc3NpbmcgdmFsdWVzLgoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwPSdUaGUgcGxvdCBzaG93cyB0aGUgY29tcGFyaXNvbiBiZXR3ZWVuIHRoZSBvcmlnaW5hbCBkYXRhIGNvbnRhaW5pbmcgbWlzc2luZyB2YWx1ZXMgZm9yIHRoZSB2YXJpYWJsZXMgaGVhcnQgZGlzZWFzZSBhbmQgc21va2luZyBoaXN0b3J5LCBhbmQgdGhlIGRhdGEgYWZ0ZXIgdXNpbmcgbW9kZSBpbXB1dGUuIFRoZSBoaXN0b2dyYW1zIHNob3cgdGhhdCBtb2RlIGltcHV0ZSB1c2VkIHdoYXQgd2FzIG1vc3QgY29tbW9uIHRvIHJlcGxhY2UgdGhlIG1pc3NpbmcgdmFsdWVzLiBUaGlzIGlzIHNlZW4gY2xlYXJseSBpbiB0aGUgdmFyaWFibGUgc21va2luZyBoaXN0b3J5LCB3aGVyZSB0aGUgY2F0ZWdvcnkgbmV2ZXIgd2VudCBmcm9tIG9yaWdpbmFsbHkgYSBjb3VudCBvZiBhYm91dCA0MCwwMDAgdG8gYWJvdXQgNzAsMDAwLiBIZWFydCBkaXNlYXNlIGhhZCBhIHNtYWxsIGFtb3VudCBvZiBtaXNzaW5nIGRhdGEgKG9ubHkgMTUpLCBob3dldmVyIHRoZSAxNSBtaXNzaW5nIHdlcmUgY2hhbmdlZCB0byAwLCBpbmRpY2F0aW5nIHRoZSBwYXRpZW50IHdvdWxkIG5vdCBoYXZlIGhlYXJ0IGRpc2Vhc2UuJywgZWNobz1GQUxTRX0KCgpkaWFiZXRlc2QgPC1kaWFiZXRlc2QKIyBGdW5jdGlvbiB0byBpbXB1dGUgbW9kZQoKTW9kZSA8LSBmdW5jdGlvbih4KSB7CiAgdXggPC0gdW5pcXVlKG5hLm9taXQoeCkpICAjIFJlbW92ZSBOQXMgYmVmb3JlIGNvbXB1dGluZyBtb2RlCiAgdGFiIDwtIHRhYnVsYXRlKG1hdGNoKHgsIHV4KSkKICBtb2RlX3ZhbHVlIDwtIHV4W3doaWNoLm1heCh0YWIpXQogIAogICMgRW5zdXJlIG1vZGVfdmFsdWUgaXMgb2YgdGhlIHNhbWUgdHlwZSBhcyB4CiAgaWYgKGlzLmZhY3Rvcih4KSkgewogICAgcmV0dXJuKGZhY3Rvcihtb2RlX3ZhbHVlLCBsZXZlbHMgPSBsZXZlbHMoeCkpKQogIH0gZWxzZSBpZiAoaXMuY2hhcmFjdGVyKHgpKSB7CiAgICByZXR1cm4oYXMuY2hhcmFjdGVyKG1vZGVfdmFsdWUpKQogIH0gZWxzZSB7CiAgICByZXR1cm4oYXMubnVtZXJpYyhtb2RlX3ZhbHVlKSkKICB9Cn0KI2FwcGx5IG1vZGUgaW1wdXRhdGlvbgp2YWx1ZV9pbXB1dGVkIDwtIGRhdGEuZnJhbWUoCiAgb3JpZ2luYWwgPSBkaWFiZXRlc2QkaGVhcnRfZGlzZWFzZSwKICBvcmlnaW5hbDI9ZGlhYmV0ZXNkJHNtb2tpbmdfaGlzdG9yeSwKICBpbXB1dGVkX21vZGVoZCA9IHJlcGxhY2UoZGlhYmV0ZXNkJGhlYXJ0X2Rpc2Vhc2UsIGlzLm5hKGRpYWJldGVzZCRoZWFydF9kaXNlYXNlKSwgTW9kZSgoZGlhYmV0ZXNkJGhlYXJ0X2Rpc2Vhc2UpKSksCiAgaW1wdXRlZF9tb2Rlc2ggPSByZXBsYWNlKGRpYWJldGVzZCRzbW9raW5nX2hpc3RvcnksIGlzLm5hKGRpYWJldGVzZCRzbW9raW5nX2hpc3RvcnkpLCBNb2RlKGRpYWJldGVzZCRzbW9raW5nX2hpc3RvcnkpKSkKc3VtbWFyeSh2YWx1ZV9pbXB1dGVkKQoKI3Bsb3QgdGhlIGNvbXBhcmlzb24gb2Ygb3JpZ2luYWwgZGF0YSBhbmQgbW9kZSBpbXB1dGVkIGRhdGEKaDEgPC0gZ2dwbG90KHZhbHVlX2ltcHV0ZWQsIGFlcyh4ID0gb3JpZ2luYWwpKSArCiAgZ2VvbV9iYXIoYmlucz0xMCwgZmlsbCA9ICIjYWQxNTM4IiwgY29sb3IgPSAiIzAwMDAwMCIsIHBvc2l0aW9uID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIk9yaWdpbmFsIGZvciBIZWFydCBEaXNlYXNlIikgKwogIHRoZW1lX2NsYXNzaWMoKQpoMiA8LSBnZ3Bsb3QodmFsdWVfaW1wdXRlZCwgYWVzKHggPSBvcmlnaW5hbDIpKSArCiAgZ2VvbV9iYXIoIGZpbGwgPSAiIzE1YWQ0ZiIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJPcmlnaW5hbCBmb3IgU21va2luZyBIaXN0b3J5IikgKwogIHRoZW1lX2NsYXNzaWMoKQpoMyA8LSBnZ3Bsb3QodmFsdWVfaW1wdXRlZCwgYWVzKHggPSBpbXB1dGVkX21vZGVoZCkpICsKICBnZW9tX2JhcihiaW5zPTEwLCBmaWxsID0gIiMxNTQzYWQiLCBjb2xvciA9ICIjMDAwMDAwIiwgcG9zaXRpb24gPSAiaWRlbnRpdHkiKSArCiAgZ2d0aXRsZSgiTW9kZS1pbXB1dGVkIGZvciBIZWFydCBEaXNlYXNlIikgKwogIHRoZW1lX2NsYXNzaWMoKQpoNCA8LSBnZ3Bsb3QodmFsdWVfaW1wdXRlZCwgYWVzKHggPSBpbXB1dGVkX21vZGVzaCkpICsKICBnZW9tX2JhciggZmlsbCA9ICIjYWQ4NDE1IiwgY29sb3IgPSAiIzAwMDAwMCIsIHBvc2l0aW9uID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIk1vZGUtaW1wdXRlZCBmb3IgU21va2luZyBIaXN0b3J5IikgKwogIHRoZW1lX2NsYXNzaWMoKQoKCnBsb3RfZ3JpZChoMSwgaDIsIGgzLCBoNCwgbnJvdyA9IDIsIG5jb2wgPSAyKQoKCgpgYGAKCiMjIFJlZ3Jlc3Npb24tQmFzZWQgSW1wdXRhdGlvbiBmb3IgTnVtZXJpY2FsIFZhcmlhYmxlcwoKVXNpbmcgcmVncmVzc2lvbiBtb2RlbHMsIHdlIGNhbiBlc3RpbWF0ZSBtaXNzaW5nIHZhbHVlcy4gRm9yIHRoZSB2YXJpYWJsZSwgYm1pLCB3ZSBjYW4gcHJlZGljdCB0aGUgbWlzc2luZyB2YWx1ZXMgdXNpbmcgZXN0aW1hdGVzIGZyb20gb3VyIG1vZGVsLiBCbWkgaXMgYSBjb250aW51b3VzIHZhcmlhYmxlLCB1bmxpa2UgdGhlIHByZXZpb3VzIGV4YW1wbGUgd2hlcmUgb3VyIHZhbHVlcyBjb3VsZCBvbmx5IGJlIDAgb3IgMS4gSW4gdGhpcyBtZXRob2QsIGEgbGluZWFyIG1vZGVsIHdhcyBjcmVhdGVkIHRvIGhlbHAgY3JlYXRlIGVzdGltYXRlcyBvZiBvdXIgdmFsdWVzLiAKCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0nVGhlIGJveHBsb3RzIHNob3cgdGhlIGNvbXBhcmlzb24gb2YgdGhlIHZhcmlhYmxlIGJtaSBiZWZvcmUgYW5kIGFmdGVyIHJlZ3Jlc3Npb24gaW1wdXRhdGlvbi4nIH0KCiNjcmVhdGUgYSBkYXRhc2V0IGZvciByZWdyZXNzaW9uIGltcHV0ZQpyZWdpbXB1dGU8LWRpYWJldGVzZAoKIyBJZGVudGlmeSByb3dzIHdoZXJlIEJNSSBpcyBtaXNzaW5nCm1pc3Npbmdfcm93cyA8LSB3aGljaChpcy5uYShkaWFiZXRlc2QkYm1pKSkgICMgR2V0IHJvdyBpbmRpY2VzCgoKIyBUcmFpbiBhIGxpbmVhciBtb2RlbCB1c2luZyBjb21wbGV0ZSBjYXNlcwpsbV9tb2RlbCA8LSBsbShibWkgfiBhZ2UgKyBibG9vZF9nbHVjb3NlX2xldmVsICsgSGJBMWNfbGV2ZWwgKyBoZWFydF9kaXNlYXNlICsgaHlwZXJ0ZW5zaW9uICsgZGlhYmV0ZXMsIAogICAgICAgICAgICAgICBkYXRhID0gcmVnaW1wdXRlLCBuYS5hY3Rpb24gPSBuYS5leGNsdWRlKQoKIyBJbXB1dGUgbWlzc2luZyBCTUkgdmFsdWVzIHVzaW5nIHRoZSBtb2RlbApkaWFiZXRlc2QkYm1pW21pc3Npbmdfcm93c10gPC0gcHJlZGljdChsbV9tb2RlbCwgbmV3ZGF0YSA9IHJlZ2ltcHV0ZVttaXNzaW5nX3Jvd3MsIF0pCgoKZGVwLm1pIDwtIGJpbmRfcm93cygKICBkYXRhLmZyYW1lKHZhbHVlID0gZGlhYmV0ZXNkJGJtaSwgaW1wdXRlZCA9IHJlZ2ltcHV0ZSRibWkpKQogICAgICAgICAgICAgI2ltcCA9ICJkZXAuaW1wMSIpCgoKaTc8LWJveHBsb3QoZGlhYmV0ZXNkJGJtaSwKbWFpbiA9ICJNZWFuIGJtaSBpbiBPcmlnaW5hbCBEYXRhIiwKeGxhYiA9ICJCTUkiLApjb2wgPSAiYmx1ZSIsCmJvcmRlciA9ICJibGFjayIsCmhvcml6b250YWwgPSBUUlVFLApub3RjaCA9IFRSVUUKKQppOCA8LWJveHBsb3QocmVnaW1wdXRlJGJtaSwKbWFpbiA9ICJSZWdyZXNzaW9uIEltcHV0YXRpb24gZm9yIEJNSSIsCnhsYWIgPSAiQk1JIiwKY29sID0gInJlZCIsCmJvcmRlciA9ICJibGFjayIsCmhvcml6b250YWwgPSBUUlVFLApub3RjaCA9IFRSVUUKKQoKCiAKCmBgYAoKIyMgTUlDRSBJbXB1dGF0aW9uCgpNSUNFIGlzIG11bHRpcGxlIGltcHV0YXRpb24gdGVjaG5pcXVlcyB1c2VkIHRvIGltcHV0ZSBtaXNzaW5nIHZhbHVlcy4gVGhpcyBtZXRob2QgYWxzbyB1c2VzIHJlZ3Jlc3Npb24gbW9kZWxzIGFuZCBhY2NvdW50cyBmb3IgdW5jZXJ0YWludHkgYnkgZ2VuZXJhdGluZyBtdWx0aXBsZSBwb3NzaWJsZSB2YWx1ZXMuIFVzaW5nIE1JQ0UsIHRoZSB2YXJpYWJsZXMgc21va2luZyBoaXN0b3J5LCBoZWFydCBkaXNlYXNlLCBhbmQgYm1pLCBjYW4gYmUgaW1wdXRhdGVkIHdpdGhpbiBvbmUgZnVuY3Rpb24uIE1JQ0UgY2FuIGhhbmRsZSBkaWZmZXJlbnQgdHlwZXMgb2YgdmFyaWFibGVzLCBpbXB1dGF0ZXMgYmFzZWQgb24gdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHZhcmlhYmxlcyBhbmQgaXQgYWNjb3VudHMgZm9yIHZhcmlhYmlsaXR5IGluIG1pc3NpbmcgZGF0YS4gCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0nQmFzZWQgb24gdGhlIHRocmVlIGdyYXBocywgTUlDRSBzZWVtcyB0byBoYXZlIHByb2R1Y2VkIHZhbHVlcyB0aGF0IGFwcGVhciBhbG1vc3QgaWRlbnRpY2FsIHRvIHRoZSBvcmlnaW5hbCBkYXRhc2V0LiBNb2RlIGltcHV0ZSBzZWVtcyB0byBiZSBzbGlnaHRseSBkaWZmZXJlbnQgc2luY2UgaXQgcmVsaWVzIG9uIGZpbGxpbmcgbWlzc2luZyB2YWx1ZXMgd2l0aCB0aGUgbW9zdCBjb21tb24gdmFsdWUuIEluIHRoaXMgY2FzZSwgbW9kZSBpbXB1dGUgZmlsbGVkIGFsbCBtaXNzaW5nIHZhbHVlcyBhcyAwIGFuZCB1bmRlci1yZXByZXNlbnRlZCAxLicsIGVjaG89RkFMU0V9CgojcmVsb2FkIGRhdGFzZXQgc28gdGhhdCBpdCBpcyBmcmVlIG9mIG1vZGUgYW5kIHJlZ3Jlc3Npb24gaW1wdXRhdGlvbiBkb25lIHByZXZpb3VzbHkKZGF0YTIgPC0gcmVhZC5jc3YoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9HYWJieUs4L0RhdGFzZXRzL3JlZnMvaGVhZHMvbWFpbi9kaWFiZXRlc19wcmVkaWN0aW9uX2RhdGFzZXQuY3N2JykKCiNjcmVhdGUgbWlzc2luZyB2YWx1ZXMgYW5kIG1ha2Ugc21va2luZyBoaXN0b3J5IGEgYmluYXJ5IHZhcmlhYmxlCmx0ci5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjEwMDAsIDUwLCByZXBsYWNlID0gRkFMU0UpCmdwYS5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjEwMDAsIDE1LCByZXBsYWNlID0gRkFMU0UpIApkYXRhMiRzbW9raW5nX2hpc3RvcnlbZGF0YTIkc21va2luZ19oaXN0b3J5PT0gIk5vIEluZm8iXSA8LU5BCmRhdGEyJGJtaVtsdHIubWlzc2luZy5pZF0gPC0gTkEKZGF0YTIkaGVhcnRfZGlzZWFzZVtncGEubWlzc2luZy5pZF0gPC0gTkEKCiNtYWtlIHZhcmlhYmxlcyBudW1lcmljCmRhdGEyJGdlbmRlciA8LSBhcy5udW1lcmljKGFzLmZhY3RvcihkYXRhMiRnZW5kZXIpKQpkYXRhMiRoZWFydF9kaXNlYXNlPC0gYXMuZmFjdG9yKGFzLm51bWVyaWMoZGF0YTIkaGVhcnRfZGlzZWFzZSkpCmRhdGEyJHNtb2tpbmdfaGlzdG9yeTwtYXMuZmFjdG9yKGRhdGEyJHNtb2tpbmdfaGlzdG9yeSkKI2FwcGx5IE1JQ0UgaW1wdXRhdGlvbgpkZl9taWNlIDwtIG1pY2UoZGF0YTIsIG1ldGhvZCA9IGMoIiIsIiIsIiIsInBtbSIsInBvbHlyZWciLCJwbW0iLCIiLCIiLCIiKSwgIG0gPSAyMCwgbWF4aXQ9MjAsc2VlZCA9IDEyMywgcHJpbnQ9RikKCiMgQ29tcGxldGUgZGF0YXNldCB3aXRoIGltcHV0ZWQgdmFsdWVzCmRmX2ltcHV0ZWQgPC0gY29tcGxldGUoZGZfbWljZSkKCiNwbG90IGNvbXBhcmlzb25zIG9mIGJlZm9yZSBhbmQgYWZ0ZXIgTUlDRSBpbXB1dGF0aW9uIGZvciBoZWFydCBkaXNlYXNlCmcxIDwtIGdncGxvdCh2YWx1ZV9pbXB1dGVkLCBhZXMoeCA9IGltcHV0ZWRfbW9kZWhkKSkgKwogIGdlb21fYmFyKGZpbGwgPSAiIzE1NDNhZCIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJNb2RlLWltcHV0ZWQiKSArCiAgbGFicyh4PSJIZWFydCBEaXNlYXNlIikrCiAgdGhlbWVfY2xhc3NpYygpCmcyIDwtIGdncGxvdCh2YWx1ZV9pbXB1dGVkLCBhZXMoeCA9IG9yaWdpbmFsKSkgKwogIGdlb21fYmFyKGZpbGwgPSAiI2FkMTUzOCIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJPcmlnaW5hbCIpICsKICBsYWJzKHg9IkhlYXJ0IERpc2Vhc2UiKSsKICB0aGVtZV9jbGFzc2ljKCkKZzMgPC0gZ2dwbG90KGRmX2ltcHV0ZWQsIGFlcyh4ID0gaGVhcnRfZGlzZWFzZSkpICsKICBnZW9tX2JhcihmaWxsID0gInB1cnBsZSIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJNSUNFIikgKwogIGxhYnMoeD0iSGVhcnQgRGlzZWFzZSIpKwogIHRoZW1lX2NsYXNzaWMoKQpwbG90X2dyaWQoZzEsIGcyLCBnMywgbnJvdz0xLCBuY29sID0zKQpgYGAKCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0gJ1RoZSBiYXIgZ3JhcGhzIHNob3cgdGhlIGNvbXBhcmlzb24gb2YgdGhlIG9yaWdpbmFsIGRhdGEgdG8gbW9kZSBpbXB1dGF0aW9uIGFuZCBNSUNFLiBNSUNFIGFwcGVhcnMgdG8gaGF2ZSBkaXNwZXJzZWQgdGhlIGRhdGEgbW9yZSBldmVubHkgYWNyb3NzIHRoZSBkaWZmZXJlbnQgY2F0ZWdvcmllcywgd2hpbGUgbW9kZSBpbXB1dGF0aW9uIGhhcyBvbmx5IGFkZGVkIHZhbHVlcyB0byB0aGUgY2F0ZWdvcnkgbmV2ZXIuJ30KI3Bsb3QgY29tcGFyaXNvbnMgZm9yIHNtb2tpbmcgaGlzdG9yeQpnNCA8LSBnZ3Bsb3QoZGZfaW1wdXRlZCwgYWVzKHggPSBzbW9raW5nX2hpc3RvcnkpKSArCiAgZ2VvbV9iYXIoIGZpbGwgPSAicHVycGxlIiwgY29sb3IgPSAiIzAwMDAwMCIsIHBvc2l0aW9uID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIk1JQ0UiKSArCiAgbGFicyh4PSJTbW9raW5nIEhpc3RvcnkiKSsKICB0aGVtZV9jbGFzc2ljKCkKZzUgPC0gZ2dwbG90KHZhbHVlX2ltcHV0ZWQsIGFlcyh4ID0gb3JpZ2luYWwyKSkgKwogIGdlb21fYmFyKCBmaWxsID0gInJlZCIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJPcmlnaW5hbCBTbW9raW5nIEhpc3RvcnkiKSArCiAgbGFicyh4PSJTbW9raW5nIEhpc3RvcnkiKSsKICB0aGVtZV9jbGFzc2ljKCkKZzYgPC0gZ2dwbG90KHZhbHVlX2ltcHV0ZWQsIGFlcyh4ID0gaW1wdXRlZF9tb2Rlc2gpKSArCiAgZ2VvbV9iYXIoIGZpbGwgPSAiYmx1ZSIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJNb2RlLWltcHV0ZWQiKSArCiAgbGFicyh4PSJTbW9raW5nIEhpc3RvcnkiKSsKICB0aGVtZV9jbGFzc2ljKCkKcGxvdF9ncmlkKGc0LGc1LGc2LCBucm93PTMsIG5jb2w9MSkKYGBgCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0nVGhlIGJveHBsb3RzIHNob3cgdGhlIGNvbXBhcmlzb24gb2YgdGhlIG9yaWdpbmFsIGRhdGEgdG8gYm90aCBNSUNFIGFuZCByZWdyZXNzaW9uIGltcHV0YXRpb24uIFRoZSBhcHBlYXIgdG8gaGF2ZSBzaW1pbGFyIHJlc3VsdHMsIGJhc2VkIG9uIG1lYW4gd2hpY2ggaXMgaW5kaWNhdGVkIGJ5IHRoZSBibGFjayBsaW5lIHdpdGhpbiBlYWNoIGJveC4nfQoKI3Bsb3QgY29tcGFyaXNvbnMgZm9yIGJtaQpnNzwtYm94cGxvdChkaWFiZXRlc2QkYm1pLAptYWluID0gIk1lYW4gQk1JIGluIE9yaWdpbmFsIERhdGEiLAp4bGFiID0gIkJNSSIsCmNvbCA9ICJibHVlIiwKYm9yZGVyID0gImJsYWNrIiwKaG9yaXpvbnRhbCA9IFRSVUUsCm5vdGNoID0gVFJVRQopCmc4IDwtYm94cGxvdChyZWdpbXB1dGUkYm1pLAptYWluID0gIlJlZ3Jlc3Npb24gSW1wdXRhdGlvbiBmb3IgQk1JIiwKeGxhYiA9ICJCTUkiLApjb2wgPSAicmVkIiwKYm9yZGVyID0gImJsYWNrIiwKaG9yaXpvbnRhbCA9IFRSVUUsCm5vdGNoID0gVFJVRQopCmc5IDwtYm94cGxvdChkZl9pbXB1dGVkJGJtaSwKbWFpbiA9ICJNSUNFIGZvciBCTUkiLAp4bGFiID0gIkJNSSIsCmNvbCA9ICJwdXJwbGUiLApib3JkZXIgPSAiYmxhY2siLApob3Jpem9udGFsID0gVFJVRSwKbm90Y2ggPSBUUlVFCikKCgoKYGBgCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTV9Cm1vZGVsNSA8LSB3aXRoKGRmX21pY2UsIGxtKGRpYWJldGVzIH4gYm1pKyBoZWFydF9kaXNlYXNlKyBzbW9raW5nX2hpc3RvcnkgKSkKc3VtbWFyeShwb29sKG1vZGVsNSkpIAoKCmBgYAoKVGhlIHN0YXRpc3RpY3MgYWJvdmUgc2hvdyB0aGUgc3VtbWFyeSBvZiB0aGUgbmV3bHkgaW1wdXRlZCBtaXNzaW5nIHZhcmlhYmxlcyB0aHJvdWdoIE1JQ0UuIEJhc2VkIG9uIG91ciBwLXZhbHVlcywgc21va2luZyBoaXN0b3J5IHdpbGwgbW9zdCBsaWtlbHkgbm90IGJlIGNob3NlbiBmb3IgdGhlIGZpbmFsIG1vZGVsIGFzIGl0J3Mgc2lnbmlmaWNhbmNlIGxldmVsIGlzIGdyZWF0ZXIgdGhhbiAwLjA1LCBpbmRpY2F0aW5nIGFuIGluc2lnbmlmaWNhbnQgcHJlZGljdG9yIHZhcmlhYmxlLiAKCgojIFNrZXduZXNzCgpTa2V3bmVzcyBpcyBhIG1lYXN1cmUgb2Ygc3ltbWV0cnkgd2l0aGluIGEgZGlzdHJpYnV0aW9uLiBUaGUgc2tld25lc3MgbWVhc3VyZW1lbnRzIGJlbG93IGFyZSBvZiB0aGUgdmFyaWFibGVzIGFnZSwgYm1pLCBIYkExYyBsZXZlbCwgYW5kIGJsb29kIGdsdWNvc2UgbGV2ZWwsIHJlc3BlY3RpdmVseS4gV2hlbiBza2V3bmVzcyBpcyBlcXVhbCB0byAwLCB3ZSBjYW4gYXNzdW1lIHRoZSBkYXRhIGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBXaGVuIHNrZXduZXNzIGlzIGdyZWF0ZXIgdGhhbiAwLCBvdXIgZGF0YSBpcyBwb3NpdGl2ZWx5IHNrZXdlZCwgd2hpbGUgYSB2YWx1ZSBsZXNzIHRoYW4gemVybyBpbmRpY2F0ZXMgbmVnYXRpdmVseSBza2V3ZWQgZGF0YS4gRm9yIHRoZSBkaWFiZXRlcyBkYXRhc2V0LCB0aGUgdmFyaWFibGVzIGJtaSBhbmQgYmxvb2QgZ2x1Y29zZSBsZXZlbCBhcmUgMSBvciBhYm91dCAxLCB3aGljaCBpbmRpY2F0ZSBhIHNpZ25pZmljYW50IHJpZ2h0IHNrZXcgaW4gdGhlIGRpc3RyaWJ1dGlvbi4gCmBgYHtyfQoKCgphZ2UxPC0gc2tld25lc3MoZGZfaW1wdXRlZCRhZ2UpIApibWkxPC1za2V3bmVzcyhkZl9pbXB1dGVkJGJtaSkgCkhiQTFjMTwtc2tld25lc3MoIGRmX2ltcHV0ZWQkSGJBMWNfbGV2ZWwpIApnbHVjb3NlMTwtc2tld25lc3MoZGZfaW1wdXRlZCRibG9vZF9nbHVjb3NlX2xldmVsKQoKbXl0YWJsZTwtZGF0YS5mcmFtZShhZ2UxLGJtaTEsSGJBMWMxLCBnbHVjb3NlMSkKcGFuZGVyKG15dGFibGUsIGNhcHRpb249ICJTa2V3bmVzcyBvZiBOdW1lcmljIFZhcmlhYmxlcyIscG9zaXRpb249ImNlbnRlciIpCgpgYGAKCgoKCiMgVHJhbnNmb3JtaW5nIERhdGEKClRvIGhhbmRsZSBvdXIgc2tld2VkIHZhcmlhYmxlcywgd2UgY2FuIG5vcm1hbGl6ZSB0aGUgdmFyaWFibGVzIGJtaSBhbmQgYmxvb2QgZ2x1Y29zZSBsZXZlbC4gTm9ybWFsaXphdGlvbiByZXNjYWxlcyBkYXRhIGludG8gYSBmaXhlZCByYW5nZSBvZiBbMCwxXS4gQnkgbm9ybWFsaXppbmcgb3VyIGRhdGEsIHdlIGNhbiBmaXggc2tld25lc3MgYW5kIGNyZWF0ZSBub3JtYWxseSBkaXN0cmlidXRlZCBkYXRhLiBUaGUgdmFyaWFibGVzLCBhZ2UgYW5kIEhiQTFjIGxldmVsIGhhdmUgYmVlbiBzdGFuZGFyZGl6ZWQgdG8ga2VlcCB0aGUgZGlzdHJpYnV0aW9uIGNlbnRlcmVkLiBTdGFuZGFyZGl6YXRpb24gaXMgdXNlZCB0byBjcmVhdGUgYSBtZWFuIG9mIDAgYW5kIGEgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIDEsIHRvIGZvbGxvdyBhIG5vcm1hbCBkaXN0cmlidXRpb24uIEJhc2VkIG9uIHRoZSByZXN1bHRzIGJlbG93LCB3ZSBjYW4gc2VlIHRoYXQgdGhlIHRyYW5zZm9ybWF0aW9uIGhhcyBjb3JyZWN0ZWQgdGhlIHJpZ2h0IHNrZXcgaW4gdGhlIGRhdGEgZnJvbSBiZWZvcmUuCgoKYGBge3J9CmRmX3RyYW5zIDwtIGRmX2ltcHV0ZWQgICMgQ29weSBvcmlnaW5hbCBkYXRhc2V0IGFmdGVyIE1JQ0UKCiNlbnN1cmUgZGlhYmV0ZXMgaXMgbnVtZXJpYyBhbmQgYSBmYWN0b3IKZGZfdHJhbnMkZGlhYmV0ZXM8LSBhcy5udW1lcmljKGFzLmZhY3RvcihkZl90cmFucyRkaWFiZXRlcykpCiMgTWluLU1heCBOb3JtYWxpemF0aW9uCm5vcm1hbGl6ZSA8LSBmdW5jdGlvbih4KSB7CiAgaWYgKG1heCh4KSAtIG1pbih4KSA9PSAwKSByZXR1cm4ocmVwKDAsIGxlbmd0aCh4KSkpICAjIFByZXZlbnQgZGl2aXNpb24gYnkgemVybwogIHJldHVybigoeCAtIG1pbih4KSkgLyAobWF4KHgpIC0gbWluKHgpKSkKfQoKI2FwcGx5IG5vcm1hbGl6YXRpb24KZGZfdHJhbnMkYm1pIDwtIG5vcm1hbGl6ZShkZl9pbXB1dGVkJGJtaSkKZGZfdHJhbnMkYmxvb2RfZ2x1Y29zZV9sZXZlbCA8LSBub3JtYWxpemUoZGZfaW1wdXRlZCRibG9vZF9nbHVjb3NlX2xldmVsKQoKIyBaLVNjb3JlIFN0YW5kYXJkaXphdGlvbgpzdGFuZGFyZGl6ZSA8LSBmdW5jdGlvbih4KSB7CiAgcmV0dXJuKCh4IC0gbWVhbih4LCBuYS5ybSA9IFRSVUUpKSAvIHNkKHgsIG5hLnJtID0gVFJVRSkpCn0KCiNhcHBseSBzdGFuZGFyZGl6YXRpb24KZGZfdHJhbnMkYWdlIDwtIHN0YW5kYXJkaXplKGRmX3RyYW5zJGFnZSkKZGZfdHJhbnMkSGJBMWNfbGV2ZWwgPC0gc3RhbmRhcmRpemUoZGZfdHJhbnMkSGJBMWNfbGV2ZWwpCgojIEFwcGx5IExvZyBUcmFuc2Zvcm1hdGlvbiB0byBGaXggU2tld25lc3MgKGlmIG5lY2Vzc2FyeSkKZGZfdHJhbnMkYm1pIDwtIGxvZzFwKGRmX3RyYW5zJGJtaSkgICMgbG9nKDEgKyB4KSBhdm9pZHMgbG9nKDApIGlzc3VlcwpkZl90cmFucyRibG9vZF9nbHVjb3NlX2xldmVsIDwtIGxvZzFwKGRmX3RyYW5zJGJsb29kX2dsdWNvc2VfbGV2ZWwpCgpibWkyIDwtIHNrZXduZXNzKGRmX3RyYW5zJGJtaSkKYWdlMiA8LSBza2V3bmVzcyhkZl90cmFucyRhZ2UpCkhiQTFjMjwtIHNrZXduZXNzKGRmX3RyYW5zJEhiQTFjX2xldmVsKQpnbHVjb3NlMjwtIHNrZXduZXNzKGRmX3RyYW5zJGJsb29kX2dsdWNvc2VfbGV2ZWwpCgpuZXd0YWJsZTwtZGF0YS5mcmFtZShibWkyLGFnZTIsSGJBMWMyLGdsdWNvc2UyKQpwYW5kZXIobmV3dGFibGUsIGNhcHRpb249Ik5ld2x5IFRyYW5zZm9ybWVkIERhdGEiLCBwb3NpdGlvbj0iY2VudGVyIikKCgpgYGAKClRyYW5zZm9ybWluZyBvdXIgZGF0YSBoYXMgc3VjY2Vzc2Z1bGx5IGRlY3JlYXNlZCBza2V3bmVzcyBpbiBvdXIgdmFyaWFibGVzLiBXZSBjYW4gc2VlIGJtaSBhbmQgYmxvb2QgZ2x1Y29zZSBsZXZlbCBhcmUgbm8gbG9uZ2VyIGFib3V0IDEuIAoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwPSdXZSBjYW4gc2VlIGluIHRoZSBncmFwaHMgYWJvdmUgdGhhdCBhZnRlciB0cmFuc2Zvcm1pbmcgdGhlIGRhdGFzZXQsIHRoZSBkYXRhIHNlZW1zIHRvIGZvbGxvdyBhIG5vcm1hbCBkaXN0cmlidXRpb24gbW9yZSBjbG9zZWx5LlRoaXMgaXMgYXBwYXJlbnQgaW4gdGhlIGhpc3RvZ3JhbXMgYXBwZWFyaW5nIG1vcmUgaW4gYSBiZWxsIHNoYXBlIGN1cnZlLicgfQoKIyBDb21iaW5lIG9sZCBhbmQgbmV3IGRhdGEgZm9yIGNvbXBhcmlzb24KZGZfY29tcGFyZSA8LSBkYXRhLmZyYW1lKAogIGJtaV9vcmlnaW5hbCA9IGRmX2ltcHV0ZWQkYm1pLAogIGJtaV90cmFuc2Zvcm1lZCA9IGRmX3RyYW5zJGJtaSwKICBibG9vZF9nbHVjb3NlX29yaWdpbmFsID0gZGZfaW1wdXRlZCRibG9vZF9nbHVjb3NlX2xldmVsLAogIGJsb29kX2dsdWNvc2VfdHJhbnNmb3JtZWQgPSBkZl90cmFucyRibG9vZF9nbHVjb3NlX2xldmVsCikKCiMgUmVzaGFwZSBkYXRhIGZvciBnZ3Bsb3QKZGZfbG9uZyA8LSBtZWx0KGRmX2NvbXBhcmUpCgojIFBsb3QgaGlzdG9ncmFtcwpnZ3Bsb3QoZGZfbG9uZywgYWVzKHggPSB2YWx1ZSwgZmlsbCA9IHZhcmlhYmxlKSkgKwogIGdlb21faGlzdG9ncmFtKGFscGhhID0gMC42LCBiaW5zID0gMzAsIHBvc2l0aW9uID0gImlkZW50aXR5IikgKwogIGZhY2V0X3dyYXAofiB2YXJpYWJsZSwgc2NhbGVzID0gImZyZWUiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIkNvbXBhcmlzb24gb2YgT3JpZ2luYWwgdnMuIFRyYW5zZm9ybWVkIERhdGEiLCB4ID0gIlZhbHVlIiwgeSA9ICJDb3VudCIpCgoKYGBgCgoKCgojIEFuYWx5emluZyBEYXRhClRoZSBuZXh0IHN0ZXAgaXMgdG8gZmluZCB3aGljaCB2YXJpYWJsZXMgYXJlIHNpZ25pZmljYW50bHkgaW1wb3J0YW50IHdoZW4gdHJ5aW5nIHRvIHByZWRpY3QgZGlhYmV0ZXMuIEJ5IHVzaW5nIGZlYXR1cmUgc2VsZWN0aW9uLCB3ZSBhcmUgYWJsZSB0byBwcmVkaWN0IHBvc3NpYmxlIGJlc3QgZml0IG1vZGVscyBmb3Igb3VyIHZhcmlhYmxlLCBkaWFiZXRlcy4gRm9yIHRoaXMgZGF0YSwgd2Ugd2lsbCBmb2N1cyBvbiBsb2dpc3RpYyByZWdyZXNzaW9uLiBUaGUgdmFyaWFibGVzIG9mIGludGVyZXN0LCBkaWFiZXRlcywgaXMgYSBiaW5hcnkgdmFyaWFibGUgaW5kaWNhdGluZyBsaW5lYXIgcmVncmVzc2lvbiB3b3VsZCBub3QgbWFrZSBhbiBpZGVhbCBtb2RlbC4gCgoKCiMjIFJhbmRvbSBGb3Jlc3QKRmlyc3QsIHdlIHdpbGwgbG9vayBhdCB0aGUgYmVzdCBtb2RlbCBzZWxlY3RlZCBieSBmZWF0dXJlIHNlbGVjdGlvbiB0aHJvdWdoIHJhbmRvbSBmb3Jlc3Q6CmBgYHtyfQoKIyBQcmVwYXJlIHRoZSBkYXRhCmRmX3RyYW5zJGRpYWJldGVzIDwtIGFzLmZhY3RvcihkZl90cmFucyRkaWFiZXRlcykKCgojIFNldCB1cCBSRkUgY29udHJvbCB3aXRoIHJhbmRvbSBmb3Jlc3QKY29udHJvbCA8LSByZmVDb250cm9sKGZ1bmN0aW9ucyA9IHJmRnVuY3MsIG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDEwKQoKIyBBcHBseSBSRkUgdG8gaWRlbnRpZnkgdG9wIGZlYXR1cmVzCnJlc3VsdHMgPC0gcmZlKAogIHggPSBkZl90cmFuc1ssICFjb2xuYW1lcyhkZl90cmFucykgJWluJSAiZGlhYmV0ZXMiXSwKICB5ID0gZGZfdHJhbnMkZGlhYmV0ZXMsCiAgc2l6ZXMgPSBjKDE6OSksCiAgcmZlQ29udHJvbCA9IGNvbnRyb2wKKQoKIyBQcmludCB0aGUgc2VsZWN0ZWQgZmVhdHVyZXMKbW9kZWxzPC1kYXRhLmZyYW1lKHByZWRpY3RvcnMocmVzdWx0cykpCnBhbmRlcihtb2RlbHMsIGNhcHRpb249IlJhbmRvbSBGb3Jlc3QgU2VsZWN0ZWQgTW9kZWwiLHBvc2l0aW9uPSJjZW50ZXIiKQoKCmBgYAoKVGhlIHRhYmxlIHNob3dzIHRoZSBzZWxlY3RlZCB2YXJpYWJsZXMgcmFuZG9tIGZvcmVzdCBoYXMgc2VsZWN0ZWQgdG8gdXNlIGZvciBvdXIgbW9kZWwKCgojIyBTdGVwd2lzZSBMb2dpc3RpYyBSZWdyZXNzaW9uCk5leHQsIGxldCdzIGxvb2sgYW5kIHN0ZXB3aXNlIGxvZ2lzdGljIHJlZ3Jlc3Npb24KCmBgYHtyfQojU3RlcHdpc2UgTG9naXN0aWMgUmVncmVzc2lvbgojIEZpdCBhIGZ1bGwgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCB3aXRoIGFsbCBwcmVkaWN0b3JzCmZ1bGxfbW9kZWwgPC0gZ2xtKGRpYWJldGVzIH4gLiwgZGF0YSA9IGRmX3RyYW5zLCBmYW1pbHkgPSBiaW5vbWlhbCkKCiMgUGVyZm9ybSBzdGVwd2lzZSBzZWxlY3Rpb24gKGRlZmF1bHQgaXMgYmFja3dhcmQgZWxpbWluYXRpb24pCnN0ZXBfbW9kZWwxIDwtIHN0ZXAoZnVsbF9tb2RlbCwgZGlyZWN0aW9uID0gImJvdGgiKQpwYW5kZXIoc3VtbWFyeShzdGVwX21vZGVsMSkpCgpgYGAKClRoZSBjb2VmZmljaWVudHMgc2hvd24gYWJvdmUgYXJlIHRoZSBvbmVzIHN0ZXB3aXNlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gaGFzIGNob3NlbiBmb3IgdGhlIGZpbmFsIG1vZGVsLiBUaGV5IGFyZSBIYkExYyBsZXZlbCwgYmxvb2QgZ2x1Y29zZSBsZXZlbCwgYm1pLCBoeXBlcnRlbnNpb24sIGdlbmRlciwgYW5kIGFnZS4gCgpCb3RoIHNlbGVjdGlvbiB0eXBlcyBzZWxlY3RlZCB0aGUgc2FtZSBtb2RlbCEgSG93ZXZlciBJIHdpbGwgc3RpbGwgZ28gdGhyb3VnaCB0aGUgc3RlcHMgb2YgY3Jvc3MtdmFsaWRhdGlvbiBhcyB0aG91Z2ggSSB3YXMgY29tcGFyaW5nIHRoZSB0d28gbW9kZWxzLgoKIyBDcm9zcy1WYWxpZGF0aW9uCgpMZXQncyBleHBsb3JlIGNyb3NzLXZhbGlkYXRpb24gdG8gc2VlIHdoaWNoIG1vZGVsIGlzIGJlc3QgZml0LiBGb3IgbG9naXN0aWMgcmVncmVzc2lvbiwgaXQgaXMgbWVhbmluZ2Z1bCB0byBsb29rIGF0IGFjY3VyYWN5IGFuZCBrYXBwYS4gCmBgYHtyfQoKI2FkZCBjbGFzc2lmaWNhdGlvbgpkZl90cmFucyRkaWFiZXRlczwtIGZhY3RvcihpZmVsc2UoZGZfdHJhbnMkZGlhYmV0ZXM9PTEsICJZZXMiLCJObyIpKQoKdHJhaW5fY29udHJvbCA8LSB0cmFpbkNvbnRyb2woCiAgbWV0aG9kID0gImN2IiwgICAgICAgICAjIGNyb3NzLXZhbGlkYXRpb24KICBudW1iZXIgPSAxMCwgICAgICAgICAgICMgMTAtZm9sZAogIGNsYXNzUHJvYnMgPSBUUlVFICMgdXNlIGlmIHlvdSdyZSB0cmFja2luZyBBVUMsIFNlbnNpdGl2aXR5LCBldGMuCikKCiNydW4gQ1YgbW9kZWwKY3ZfbW9kZWwgPC0gdHJhaW4oCiAgZGlhYmV0ZXMgfiBoeXBlcnRlbnNpb24gKyBnZW5kZXIgK2FnZSArIEhiQTFjX2xldmVsICsgYmxvb2RfZ2x1Y29zZV9sZXZlbCArIGhlYXJ0X2Rpc2Vhc2UgKyBibWksIAogIGRhdGE9ZGZfdHJhbnMsIAogIG1ldGhvZCA9ICJnbG0iLCAKICBmYW1pbHkgPSAiYmlub21pYWwiLCAKICB0ckNvbnRyb2wgPSB0cmFpbl9jb250cm9sCiAgKQoKcGFuZGVyKHByaW50KGN2X21vZGVsKSkKCmBgYAoKQWNjdXJhY3kgc2hvd3MgdGhlIG92ZXJhbGwgY29ycmVjdG5lc3Mgb2YgdGhlIG1vZGVsIHByZWRpY3Rpb25zIGFuZCBrYXBwYSBtZWFzdXJlcyB0aGUgbGV2ZWxzIG9mIGFncmVlbWVudCBiZXR3ZWVuIHZhcmlhYmxlcy4gVmFsdWVzIGNsb3NlciB0byAxIHN1Z2dlc3QgaGlnaGVyIGFjY3VyYWN5IGFuZCBiZXR0ZXIgYWdyZWVtZW50LiBUaGlzIG1vZGVsIHN1Z2dlc3RzIGhpZ2ggYWNjdXJhY3kgYW5kIGhpZ2ggYWdyZWVtZW50IGJhc2VkIG9uIHRoZSB2YWx1ZXMuCgojIFJPQyBDdXJ2ZSBhbmQgQU9DIEN1cnZlCgojIyBDb25mdXNpb24gTWF0cmljZXMKCioqUk9DKiogaXMgYWxzbyBrbm93biBhcyBSZWNlaXZlciBPcGVyYXRpbmcgQ2hhcmFjdGVyaXN0aWMgQW5hbHlzaXMuIEl0IGlzIGEgdGVjaG5pcXVlIHVzaW5nIGdyYXBocyB0aGF0IGV2YWx1YXRlcyB0aGUgcGVyZm9ybWFuY2Ugb2YgYSBiaW5hcnkgbW9kZWwuIEJlZm9yZSBwbG90dGluZyB0aGUgUk9DIGN1cnZlLCBpdCBpcyBuZWNlc3NhcnkgdG8gY2FsY3VsYXRlIHRoZSB0cnVlIHBvc2l0aXZlIHJhdGUgKFRQUikgYW5kIGZhbHNlIHBvc2l0aXZlIHJhdGUgKEZQUikuIEJlbG93LCBhcmUgY29uZnVzaW9uIG1hdHJpY2VzIHRoYXQgd2VyZSB1c2VkIHRvIGNhbGN1bGF0ZSB0aG9zZSB2YWx1ZXMuCmBgYHtyfQoKI1JPQyBhbmQgQVVDCmRmX3RyYW5zJGRpYWJldGVzIDwtIGFzLmZhY3RvcihkZl90cmFucyRkaWFiZXRlcykKCiMgZml0IGEgbG9naXN0aWMKbW9kZWwubG9naXQgPC0gZ2xtKGRpYWJldGVzIH4gYWdlICsgZ2VuZGVyKyBibWkraHlwZXJ0ZW5zaW9uICsgaGVhcnRfZGlzZWFzZSArIGJsb29kX2dsdWNvc2VfbGV2ZWwrIEhiQTFjX2xldmVsICwgZmFtaWx5ID0gYmlub21pYWwsIGRhdGEgPSBkZl90cmFucykKIyBwcmVkaWN0IHByb2JhYmlsaXR5IG9mIFAoWSA9ICJZZXMiKQpwcm9iYWJpbGl0aWVzIDwtIHJvdW5kKGFzLnZlY3RvcihwcmVkaWN0KG1vZGVsLmxvZ2l0LCB0eXBlID0gInJlc3BvbnNlIikpLDMpCiMKdGhyZXNob2xkcyA8LSBjKDAuMCwgMC4yNSwgMC41LCAwLjc1LCAxLjApCgojIExvb3AgdGhyb3VnaCB0aHJlc2hvbGRzIGFuZCBjcmVhdGUgY29uZnVzaW9uIG1hdHJpY2VzCmZvciAodGhyZXNob2xkIGluIHRocmVzaG9sZHMpIHsKICBjYXQoIlxuQ29uZnVzaW9uIE1hdHJpeCBmb3IgVGhyZXNob2xkID0iLCB0aHJlc2hvbGQsICJcbiIpCiAgCiAgIyBDb252ZXJ0IHByb2JhYmlsaXRpZXMgdG8gcHJlZGljdGlvbnMKICAjIGFtOiAxID0gbWFudWFsIHRyYW5zbWlzc2lvbiwgMCA9IGF1dG9tYXRpYyB0cmFuc21pc3Npb24KICBwcmVkaWN0aW9ucyA8LSBpZmVsc2UocHJvYmFiaWxpdGllcyA+IHRocmVzaG9sZCwgIlllcyIsICJObyIpCiAgICBhbGxfbGV2ZWxzIDwtIHVuaW9uKGxldmVscyhmYWN0b3IoZGZfdHJhbnMkZGlhYmV0ZXMpKSwgbGV2ZWxzKGZhY3RvcihwcmVkaWN0aW9ucykpKQogICAgIyBHZW5lcmF0ZSBjb25mdXNpb24gbWF0cml4CiAgY20gPC0gY29uZnVzaW9uTWF0cml4KGZhY3RvcihwcmVkaWN0aW9ucywgbGV2ZWxzPWFsbF9sZXZlbHMpLCBmYWN0b3IoZGZfdHJhbnMkZGlhYmV0ZXMsbGV2ZWxzPWFsbF9sZXZlbHMpLCBwb3NpdGl2ZSA9ICJZZXMiKQogIHByaW50KGNtJHRhYmxlKQp9CgpgYGAKCgoKIyMgUk9DIEN1cnZlCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwnVGhlIHBsb3Qgc2hvd3MgdGhlIHBhdGggb2YgdGhlIFJPQyBjdXJ2ZS4nfQoKI2NyZWF0ZSBST0MgY3VydmUKClRQUiA9IGMoMSw5MTUwMC8oOTE1MDArMCksIDkxMzU2Lyg5MTM1NisxNDQpLCA5MDYzMi8oOTA2MzIrODY4KSwgODgxNjAvKDg4MTYwKzMzNDApLCAwLyg5MTUwMCswKSkKRlBSID0gYygxLDM1Mi8oMzUyKzgxNDgpLCA0MjgyLyg0MjgyKzQyMTgpLCAzMTkzLyg1MzA3KzMxOTMpLCAyMTc4LygyMTc4KzYzMjIpLCAwLyg4NTAwKzApKQpwbG90KEZQUiwgVFBSLCB0eXBlID0gImIiLCBtYWluID0gIkFuIElsbHVzdHJhdGl2ZSBST0MgQ3VydmUiLCBjb2wgPSJibHVlIiwKICAgICB4bGFiPSIxIC0gU3BlY2lmaXR5IChGUFIpIiwgeWxhYiA9ICJTZW5zaXRpdml0eSAoVFBSKSIpCiMgYWRkIGEgb2ZmLWRpYWdvbmFsIHJlcHJlc2VudGluZyByYW5kb20gZ3Vlc3MgYWxnb3JpdGhtIGluIGJpbmFyeSBwcmVkaWN0aW9uCmFibGluZSgwLDEsIGx0eSA9IDIsIGNvbCA9ICJyZWQiKQojIGxlZ2VuZApsZWdlbmQoImJvdHRvbXJpZ2h0IiwgYygiTG9naXN0aWMgTW9kZWwiLCAiUmFuZG9tIEd1ZXNzIiksCiAgICAgICBjb2w9YygiYmx1ZSIsICJyZWQiKSwgbHR5ID0gMToyLCBidHk9Im4iLCBjZXggPSAwLjkpCmBgYAoKCgoKIyMgQVVDIChBcmVhIHVuZGVyIHRoZSBDdXJ2ZSkKCioqQVVDKiogcXVhbnRpZmllcyB0aGUgcGVyZm9ybWFuY2Ugb2YgdGhlIFJPQyBjdXJ2ZSBpbnRvIGEgc2luZ2xlIHZhbHVlIHRoYXQgcmFuZ2VzIGZyb20gMCB0byAxLiBUaGUgcGxvdCBiZWxvdyB1c2VzIHRoZSBSaWVtYW5uIFN1bSBhcHByb3hpbWF0aW9uIHRvIGVzdGltYXRlIHRoZSBhcmVhIHVuZGVyIHRoZSBjdXJ2ZS4KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCdUaGUgcGxvdCBlc3RpbWF0ZXMgdGhlIGFyZWEgb2YgdGhlIFJPQyBDdXJ2ZS4gVGhlIHJlZ2lvbiBpcyBkaXZpZGVkIGludG8gc3VicmVnaW9ucywgQSxCLCBhbmQgQy4gVGhlc2UgdmFsdWVzIGFyZSB1c2VkIHRvIGNhbGN1bGF0ZSB0aGUgYXJlYSB1bmRlciB0aGUgY3VydmUuJyB9CiNBVUMKVFBSID0gcm91bmQoYygxLDkxNTAwLyg5MTUwMCswKSwgOTEzNTYvKDkxMzU2KzE0NCksIDkwNjMyLyg5MDYzMis4NjgpLCA4ODE2MC8oODgxNjArMzM0MCksIDAvKDkxNTAwKzApKSwzKQpGUFIgPSByb3VuZChjKDEsMzUyLygzNTIrODE0OCksIDQyODIvKDQyODIrNDIxOCksIDMxOTMvKDUzMDcrMzE5MyksIDIxNzgvKDIxNzgrNjMyMiksIDAvKDg1MDArMCkpLDMpClRQUjAgPSBUUFJbNzoxXQpGUFIwID0gRlBSWzc6MV0KI3Bsb3QoRlBSMCwgVFBSMCwgdHlwZSA9ICJiIikKZGF0U2VuU3BlID0gZGF0YS5mcmFtZShUUFIwLCBGUFIwKQpnZ1JPQyA9IGdncGxvdChkYXRhID0gZGF0U2VuU3BlLCBhZXMoeCA9IEZQUjAsIHk9VFBSMCkpICsKICAgICAgICBnZW9tX2xpbmUoY29sID0gInN0ZWVsYmx1ZSIpICsKICAgICAgICBnZW9tX3BvaW50KGNvbCA9ICJyZWQiKSArCiAgICAgICAgZ2VvbV9zZWdtZW50KHggPSBGUFIwLCB5ID0gMCwgeGVuZCA9IEZQUjAsIHllbmQgPSBUUFIwLCBjb2xvciA9IDQpICsKICAgICAgICBnZW9tX3NlZ21lbnQoeCA9IDAsIHkgPSAwLCB4ZW5kID0gRlBSMFs3XSwgeWVuZCA9IDAsIGNvbG9yID0gNikgKwogICAgICAgIGdndGl0bGUoIkFwcHJveGltYXRpbmcgdGhlIEFVQyBvZiBMb2dpc3RpYyBNb2RlbCIpICsKICAgICAgICB4bGFiKCIxLXNwZWNpZmljaXR5IChGUFIpIikgKyAKICAgICAgICB5bGFiKCJTZW5zaXRpdml0eSAoVFBSKSIpICsKICAgICAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSAwLjAyNSwgeSA9IDAuMTI1LCBsYWJlbD0gIkEiKSArIAogICAgICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDAuMTA1LCB5ID0gMC41LCBsYWJlbCA9ICJCIikgKwogICAgICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDAuNjA1LCB5ID0gMC41LCBsYWJlbCA9ICJDIikgKwogICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44LCAwLjIpLAogICAgICAgICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDAuMTUsIDAuMTUsIDAuNzUsIDAuMTUpLCAiaW5jaGVzIiksCiAgICAgICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKHNpemUgPSAyLCBjb2xvdXIgPSAibmF2eSIsIGxpbmV0eXBlPTEpKQojIHBhcnRpdGlvbiB0aGUgcmVnaW9uIHVuZGVyIHRoZSBST0MgaW50byB0cmFwZXpvaWRzCmdncGxvdGx5KGdnUk9DKQpgYGAKCiMjIEFVQyBWYWx1ZQoKVGhlIGFyZSB1bmRlciB0aGUgY3VydmUgaXMgZXF1YWwgdG8gMC45Nzk1IHdoaWNoIGlzIGNsb3NlIHRvIDEsIHRodXMgaW5kaWNhdGluZyBhbiBpZGVhbCBtb2RlbC4KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCdUaGUgYXJlYSB1bmRlciB0aGUgY3VydmUgaXMgMC45Nzk1IHdoaWNoIGlzIGNsb3NlIHRvIDEsIHRoaXMgaW5kaWNhdGVzIGFuIGlkZWFsIG1vZGVsLid9CkE8LSgwLjA0MSoxKS8yCkI8LSAoKDAuNTA0LTAuMDQxKSoxKQpDPC0gKCgxLTAuNTA0KSoxKQoKQVVDPC0gQStCK0MKcGFuZGVyKEFVQywgY2FwdGlvbj0gIkFyZWEgdW5kZXIgdGhlIEN1cnZlIiwgcG9zaXRpb249IkNlbnRlciIpCgpgYGAKCiMgQ29uY2x1c2lvbiBmb3IgTW9kZWwgRml0Ck91ciBiZXN0IGZpdCBtb2RlbCBpcyA6CiQkClx0ZXh0eyBEaWFiZXRlc30gPSA5Ljk5IC0gMC4yN1x0aW1lcyBcdGV4dHtnZW5kZXJ9IC0gMS4wM1x0aW1lcyBcdGV4dHthZ2V9ICAtMC44XHRpbWVzIFx0ZXh0e2h5cGVydGVuc2lvbn0gLSAwLjc2XHRpbWVzIFx0ZXh0e2hlYXJ0IGRpc2Vhc2V9IC0xMC4yNFx0aW1lcyBcdGV4dHtibWl9IC0gMi40OVx0aW1lcyBcdGV4dHtIYkExYyBsZXZlbH0gLTEwLjNcdGltZXMgXHRleHR7Ymxvb2QgZ2x1Y29zZSBsZXZlbH0KJCQKCgpUaGUgYmVzdCBmaXQgbW9kZWwgd2FzIHNlbGVjdGVkIGJhc2VkIG9uIGEgdmFyaWV0eSBvZiBkaWZmZXJlbnQgZmVhdHVyZXMuIEJvdGggc3RlcHdpc2Ugc2VsZWN0aW9uIGFuZCByYW5kb20gZm9yZXN0IHNlbGVjdGVkIHRoZSBtb2RlbCBhcyBiZXN0IGZpdC4gQWZ0ZXIgcnVubmluZyBwZXJmb3JtYW5jZSBhbmFseXNlcyBvbiB0aGUgbW9kZWwsIHRoZSBtb2RlbCB3YXMgc2hvd24gdG8gYmUgb2YgaGlnaCBwZXJmb3JtYW5jZS4gVGhpcyBtZWFucyB0aGF0IHRoZSB2YXJpYWJsZXMgY2hvc2VuIGZvciB0aGUgZmluYWwgbW9kZWwgYXJlIHNpZ25pZmljYW50IGZvciBwcmVkaWN0aW5nIGRpYWJldGVzLiBUaGUgbW9kZWwgY2hvc2Ugbm90IHRvIHNlbGVjdCBzbW9raW5nIGhpc3RvcnkgYXMgc2lnbmlmaWNhbnQgcHJlZGljdG9yIGZvciB0aGUgcmVzcG9uc2UgdmFyaWFibGUuIEEgcG9zc2libGUgc3VnZ2VzdGlvbiBmb3IgdGhpcyB3b3VsZCBiZSB0byByZWR1Y2UgdGhlIG51bWJlciBvZiByZXNwb25zZSB2YWx1ZXMgdG8gYSBiaW5hcnkgcmVzcG9uc2UuIFN1Y2ggYXMsICJIYXZlIHlvdSBldmVyIHNtb2tlZD8iIGFuZCBoYXZlIHRoZSByZXNwb25zZSBiZSAiWWVzIiBvciAiTm8iLiBUaGlzIGNvdWxkIGhlbHAgaW4gcHJlZGljdGluZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gc21va2luZyBhbmQgZGlhYmV0ZXMuIAo=